I have the following question. Which one of these is better that should be followed and why?
string strMyString = "SampleString";
or
string strMyString("SampleString");
Thanks in advance.
Compile both, look at the assembler. The first is one fewer instruction ...
; 9 : std::string f("Hello");
push OFFSET ??_C@_05COLMCDPH@Hello?$AA@
lea ecx, DWORD PTR _f$[esp+80]
call DWORD PTR __imp_??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z
; 10 : std::string g = "Hello";
push OFFSET ??_C@_05COLMCDPH@Hello?$AA@
lea ecx, DWORD PTR _g$[esp+80]
mov DWORD PTR __$EHRec$[esp+88], 0
call DWORD PTR __imp_??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z
... but that's an artifact, because it was the first one the compiler saw. Change the code by swapping the order:
; 9 : std::string g1 = "Hello";
push OFFSET ??_C@_05COLMCDPH@Hello?$AA@
lea ecx, DWORD PTR _g1$[esp+136]
call DWORD PTR __imp_??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z
; 10 : std::string f1("Hello");
push OFFSET ??_C@_05COLMCDPH@Hello?$AA@
lea ecx, DWORD PTR _f1$[esp+136]
mov DWORD PTR __$EHRec$[esp+144], 0
call DWORD PTR __imp_??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z
... and lo and behold, the second is one fewer instruction.
We also see that this compiler (Microsoft VC++ 2005, Release settings) generated the same assembler for both versions. So it makes no difference in this compiler, and you can prove it.
I answered it here
One thing i put into this answer here: Neither is using any assignment operator.
Short explanation for the string specific thing though. std::string
has a constructor taking one argument that accepts char const*
:
// simplified to a normal class declaration. std::string actually
// is a template instantiation.
class string {
public:
string(char const* str) {
// copy over...
}
};
Now you see that has a constructor taking a pointer to character(s). So that it can accept a string literal. I think the following case is obvious then:
string s("hello");
It will call the constructor directly and initialize s
thereby. This is called direct initialization.
The other way of initializing a variable is called copy initialization. The Standard says for the case of copy initialization where the initializer has not the type of the object it is initializing, the initializer is converted to the proper type.
// uses copy initialization
string s = "hello";
First, let's state the types
s
has type std::string"hello"
is an array, which in this case again is handled like a pointer. We will therefor consider it as char const*
. The compiler looks for two ways to do the conversion.
std::string
?It will create a temporary std::string
by one of those ways that is then used to initialize the object s
by using std::string
's copy constructor. And it sees std::string
has a conversion constructor that accepts the initializer. So it uses it. In the end, it is effectively the same as
std::string s(std::string("hello"));
Note that the form that is used in your example that triggered all that
std::string s = "hello";
defines an implicit conversion. You can mark the constructor taking the char const*
as explicit for your types if you wonder about the initialization rules for your stuff, and it will not allow to use the corresponding constructor as a conversion constructor anymore:
class string {
public:
explicit string(char const* str) {
// copy over...
}
};
With that, initializing it using a copy initialization
and a char const*
actually is forbidden now (and in various other places)!
Now, that was if the compiler does not support elision of temporaries at various places. The compiler is allowed to assume that a copy constructor copies in this context, and can eliminate the extra copy of the temporary string, and instead construct the temporary std::string directly into the initialized object. However, the copy constructor must be accessible in particular. So, the copy initialization is invalid if you do this
class string {
public:
explicit string(char const* str) {
// copy over...
}
private: // ugg can't call it. it's private!
string(string const&);
};
Now actually, only the direct initialization case is valid.
The only real difference is that the first one technically requires use of the copy constructor, but the compiler is allowed to elide it so that the efficiency will be identical in both cases.
However, the first requires that the copy constructor be accessible (i.e. not private), even if it isn't actually used.
The other answers are all correct, but please also remember that it probably doesn't matter. It's going to be rare, very rare, incredibly rare, that string initialization efficiency will ever impact your program's speed even by a fraction of a second.
The question itself is a fun one because it helps show the operations of C++ constructors and assignments, but in practice if you're spending time trying to optimize this (and posting on SO is evidence enough you are..) you're really tilting at windmills.
It's better to avoid the distraction and spend your effort elsewhere.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With