views:

395

answers:

5

I encountered an interesting situation today in a program where I inadvertantly assigned an unsigned integer to a std::string. The VisualStudio C++ compiler did not give any warnings or errors about it, but I happened to notice the bug when I ran the project and it gave me junk characters for my string.

This is kind of what the code looked like:

std::string my_string("");
unsigned int my_number = 1234;
my_string = my_number;

The following code also compiles fine:

std::string my_string("");
unsigned int my_number = 1234;
my_string.operator=(my_number);

The following results in an error:

unsigned int my_number = 1234;
std::string my_string(my_number);

What is going on? How come the compiler will stop the build with the last code block, but let the first 2 code blocks build?

+3  A: 

i think it accepts it as char.

ufukgun
+24  A: 

Because string is assignable from char, and int is implicitly convertible to char.

EFraim
How come the int is not implicitly casted for the last 2 blocks?What do you mean that I cannot call operator= explicitly? Because the following works: my_string.operator=("hello world");
Isn't `my_string.operator=(my_number)` an explicit call to `operator=`? What am I misunderstanding here?
sbi
"How come the int is not implicitly casted for the last 2 blocks?" Because while 1234 fits in 16 bits, and can there for be a char, not every unsigned int will fit in 16 bits. As soon as you specified a type with greater range than a char, you stopped the compiler from implicitly casting the value to a char.
Binary Worrier
Why can't you call operator= explicitly ?
CsTamas
Strange. Your second example compiles fine.
EFraim
@Binary Worrier the value does not matter, it's still an int. It will truncate the int to char.
CsTamas
Thanks, you can call operator=, at least for class types.
EFraim
Second example compiles for me too, and 13.5(4) in the standard describes the use of the function-call syntax for explicitly calling operators. I don't think there's anything wrong with example 2, other than implicitly casting an int to char, of course ;-). I wonder what the error is.
Steve Jessop
You're right...the second example does compile fine. I must have been mistaken. I'll update that.
@CsTamas: I have since seen the error of my ways, thanks :)
Binary Worrier
+11  A: 

The std::string class has the following assignment operator defined:

string& operator=( char ch );

This operator is invoked by implicit conversion of unsigned int to char.

In your third case, you are using an explicit constructor to instantiate a std::string, none of the available constructors can accept an unsigned int, or use implicit conversion from unsigned int:

string();
string( const string& s );
string( size_type length, const char& ch );
string( const char* str );
string( const char* str, size_type length );
string( const string& str, size_type index, size_type length );
string( input_iterator start, input_iterator end );
LBushkin
"operators cannot be invoked using functional call syntax". 13.5(4) in the C++ standard says they can.
Steve Jessop
"operators cannot be invoked using functional call syntax" That's plain wrong.
sbi
Shame, because the accepted answer made the same mistake at first but was voted up anyway and then corrected, whereas this answer is otherwise much better and got voted down. I'll vote for this if it's fixed.
Steve Jessop
Apparently, I am out of date on my knowledge of C++ :) I will amend my answer.
LBushkin
+2  A: 

It is definitely operator=(char ch) call - my debugger stepped into that. And my MS VS 2005 compiles following without error.

std::string my_string("");
unsigned int my_number = 1234;
my_string = my_number;
my_string.operator=(my_number);
Stanislav
A: 

I can explain the first and third situations:

my_string = 1234;

This works because string has overridden operator=(char). You are actually assigning a character (with data overflow) into the string. I don't know why the second case results in a compile error. I tried the code with GCC and it does compile.

std::string my_string(1234);

will not work, because there is no string constructor that takes a char or int argument.

Vijay Mathew