35

I am learning C++ from the beginning and I don't get the whole strings topic.

What is the difference between the following three codes?

  1. std::string s = std::string("foo");
  2. std::string s = new std::string("foo");
  3. std::string s = "foo";
Ori Popowski
  • 10,432
  • 15
  • 57
  • 79
  • 1
    Note that you generally want to use option 4: `std::string s("foo");` – Jerry Coffin Nov 09 '11 at 17:40
  • @JerryCoffin: how is that different from option 3? – Mike Seymour Nov 09 '11 at 17:41
  • 3
    @MikeSeymour: it does direct initialization instead of copy initialization. At least conceptually, #3 creates a temporary string initialized from the supplied constant, then uses the copy constructor to create `s` from that value (though, admittedly, the compiler will usually omit that, and do the equivalent of direct initialization). – Jerry Coffin Nov 09 '11 at 17:44
  • Don't forget the variants that use the uniform initialization syntax from the latest standards, i.e. `std::string s{"foo"};` – Michael Price Nov 09 '11 at 18:14

5 Answers5

56
std::string s = std::string("foo");

This creates a temporary std::string object containing "foo", then assigns it to s. (Note that compilers may elide the temporary. The temporary elison in this case is explicitly allowed by the C++ standard.)

std::string s = new std::string("foo");

This is a compiler error. The expression new std::string("foo") creates an std::string on the free store and returns a pointer to an std::string. It then attempts to assign the returned pointer of type std::string* to s of type std::string. The design of the std::string class prevents that from happening, so the compile fails.

C++ is not Java. This is not how objects are typically created, because if you forget to delete the returned std::string object you will leak memory. One of the main benefits of using std::string is that it manages the underlying string buffer for you automatically, so new-ing it kind of defeats that purpose.

std::string s = "foo";

This is essentially the same as #1. It technically initializes a new temporary string which will contain "foo", then assigns it to s. Again, compilers will typically elide the temporary (and in fact pretty much all non-stupid compilers nowadays do in fact eliminate the temporary), so in practice it simply constructs a new object called s in place.

Specifically it invokes a converting constructor in std::string that accepts a const char* argument. In the above code, the converting constructor is required to be non-explicit, otherwise it's a compiler error. The converting constructor is in fact non-explicit for std::strings, so the above does compile.

This is how std::strings are typically initialized. When s goes out of scope, the s object will be destroyed along with the underlying string buffer. Note that the following has the same effect (and is another typical way std::strings are initialized), in the sense that it also produces an object called s containing "foo".

std::string s("foo");

However, there's a subtle difference between std::string s = "foo"; and std::string s("foo");, one of them being that the converting constructor can be either explicit or non-explicit in the above case.

Community
  • 1
  • 1
In silico
  • 51,091
  • 10
  • 150
  • 143
  • 3
    +1 for being the answer that mentions compilers not necessarily creating a temporary in #1. – Joel Rondeau Nov 09 '11 at 17:39
  • 1
    Note that #1 and #3 are equivalent as far as the language is concerned. – avakar Nov 09 '11 at 17:50
  • 1
    So `std::string("foo")` creates "foo" on the stack and `new std::string("foo")` creates foo on the heap? – Ori Popowski Nov 09 '11 at 17:51
  • @Leif Ericson: Yes. (I call the "heap" the "free store".) – In silico Nov 09 '11 at 17:55
  • @LeifEricson: basically yes. The Standard amuses itself speaking of "automatic storage" for the stack and "dynamic storage" for the heap... but no implementation I know of took advantage of a different interpretation. – Matthieu M. Nov 09 '11 at 17:56
3
std::string s = std::string("foo");

This is called copy initialization. It is functionally the same as direct initialization

std::string s( "foo" );

but the former does require that the copy constructor is available and compilers may create a temporary object but most will elide the temporary and directly construct s to contain "foo".


std::string s = new std::string("foo");

This will not compile because new returns a pointer. To make it work you'd need the type of s to be a std::string *. Then the line dynamically allocates an std::string object and stores the pointer in s. You'll need to delete it once you're done using it.


std::string s = "foo";

This is almost the same as first. It is copy initialization but it has an added constraint. It requires that the std::string class contains a non-explicit constructor that takes a const char *. This allows the compiler to implicitly construct a temporary std::string object. After that the semantics are identical to case 1.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
2
  1. Creates a temporary string object and copies the value to s
  2. Does not compile, new std::string("foo") returns a pointer to some newly allocated memory. For this to work, you should declare s as a pointer to a string std::string* s.
  3. Constructs a string from a C-string.

You should use the third option in most - if not all - cases.

Kleist
  • 7,785
  • 1
  • 26
  • 30
2

1 will create a temporary variable (right hand side), then call the assignment operator to assign the value to s

2 will create an instance of std::string on the heap and return a pointer to it, and will fail in the assignment because you can't assign a pointer to a non-pointer type

3 will build a std::string and initialize it from a const char*

Fred
  • 4,894
  • 1
  • 31
  • 48
  • "you can't assign a pointer to a non-pointer type": In your opinion then `bool s; s = new std::string("Hello, world.");` is a compile-time error? BTW that equal sign is not an assignment (for example it could be legal to write `Foo x = 12;` even when `Foo::operator=(int)` is private). – 6502 Nov 09 '11 at 17:47
  • @6502: His wording is wrong, but either way it can't be assigned from a `std::string` – Mooing Duck Nov 09 '11 at 18:04
  • @MooingDuck: This answer is simply wrong on a few points: A) those are not assignments, are initializations (in C++ it's a different thing, with different rules and semantic, the assignment operator that answer talks about in 1 is *NOT* called), B) The phrase "You cannot assign a pointer to a non-pointer type" is just false ... you can assign (and also initialize) a boolean from a pointer. Point 2 has IMO a very bad wording as it looks like it's saying the code will compile and one will get a runtime error... but at least there's some doubt this is not what Fred meant. – 6502 Nov 09 '11 at 21:33
1

On the number 1, you are creating a temporary string using the constructor and then assigning it to s. Number 2 doesn't even compile. On number 3, you are creating a new string and then assign a value to it.

seth
  • 1,401
  • 1
  • 17
  • 28