-3

Just came across this. I can't believe it compiles, but it does. What kind of string initialization is this? And why do this?

std::string* name = new std::string[12];
Chris Smyth
  • 113
  • 6
  • Why do you think it shouldn't compile? –  Jan 16 '18 at 17:09
  • 3
    It's a dynamically allocated C-style array of strings (using `new[]`). You probably don't want to do this, though. – tadman Jan 16 '18 at 17:10
  • 3
    This is not an initialization of a string. It is an initialization of a string array with 12 values. – wolff Jan 16 '18 at 17:10
  • 1
    Why don't you believe it should compile? There's nothing strange going on. The [new expression](http://en.cppreference.com/w/cpp/language/new) allocates an array of 12 `std::string` objects with [dynamic storage duration](http://en.cppreference.com/w/cpp/language/storage_duration) and returns a pointer to the first element of the array. That pointer is then stored in `name`. – TypeIA Jan 16 '18 at 17:10
  • 6
    Why downvotes? The OP is misunderstanding something, but it should not be the reason to downvote the question. – SergeyA Jan 16 '18 at 17:11
  • 2
    @SergeyA Groupthink + typical C++ "I'm smarter than you" StackOverflow mentality. :( – erip Jan 16 '18 at 17:11
  • 1
    @wolff, wrong. The values are perfectly initialized. – SergeyA Jan 16 '18 at 17:11
  • 2
    @Ron It is actually initializing the 12 strings by calling the default `std::string` constructor. – TypeIA Jan 16 '18 at 17:12
  • 3
    Check out [The Definitive C++ Book Guide and List](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – molbdnilo Jan 16 '18 at 17:12
  • @SergeyA right, sorry – wolff Jan 16 '18 at 17:12
  • 1
    If you ever have to do `new std::string[..]` or `new std::string`, then your code is certainly not good. both (esp. the latter) is really bad because it completely defeats *Short String Optimizations* done in most implementations. You also run afoul of the C++'s exception safety mechanisms (aka RAII) – WhiZTiM Jan 16 '18 at 17:23
  • 1
    @UKMonkey No, they shouldn't. https://meta.stackoverflow.com/a/285777/113662 – Tadeusz Kopec for Ukraine Jan 16 '18 at 17:56
  • @TadeuszKopec Looking at the highest voted answer there - the answer as I read it is yes. – UKMonkey Jan 17 '18 at 09:42

3 Answers3

4

This is a dynamic C-style array syntax, which was in place before std::vector obsoleted all but the small fraction of this usage - and since C++11 even that smallest usage has vanished.

This code dynamically creates and initializes 12 empty strings and sets name pointer to point to the very first of them. Now those strings can be accessed with [] operator, for example:

std::cout << name[0] << "\n";

Will output empty string.

There should never be any reason to use this construct, though, and instead

std::vector<std::string> name(12);

should be used.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Not downvoter, but if I was it would be for saying use std::vector rather than std::array... (Even though I personally disagree with the existence of std::array) – UKMonkey Jan 16 '18 at 17:23
  • @UKMonkey i know not the use scenario. May be the size of the array is not known at compile time. – SergeyA Jan 16 '18 at 18:09
  • They are still clear reasons to use new[] in C++! You might not want the overhead of a vector class (for example when the array size is not evolving, or if you are building with some code that requires pointers to array, or if you need to store those pointers in another array, or avoiding memory copy etc...) – xryl669 Jan 16 '18 at 18:35
  • @xryl669 I am not seeing the reason. What is the 'overhead' of the `std::vector` you are talking about? – SergeyA Jan 16 '18 at 18:51
  • The element count and the allocated size for most implementation. That's usually 3 word per array, instead of 1 using new. If the array size does not change, you don't need to pay for storing those. I agree that new[] does store the element count in an unaccessible memory since it's required for delete[], but still... – xryl669 Jan 16 '18 at 18:55
  • 1
    @xryl669 since you would need to know the size of the array at run time to work with it (I do not think you have a program where ALL your arrays are of the same size), I find capacity a small price to pay. Show me your real use case and I will believe you. – SergeyA Jan 16 '18 at 19:03
  • Which use case for `new[]` that wasn't already obsolete with C++98 has become obsolete with C++11? – Christian Hackl Jan 16 '18 at 19:10
  • @xryl669: Don't forget that `new[]` carries its own overhead, for the compiler must use internal implementation magic to remember the number of elements for the eventual `delete[]` call. – Christian Hackl Jan 16 '18 at 19:12
  • @ChristianHackl, without `emplace_back()` one could not directly initialize the members in the vector (for non-copyable types), so people would be using placement new. With emplace back, this is no longer needed. – SergeyA Jan 16 '18 at 20:45
  • @SergeyA: But this has nothing to do with `new[]`, or does it? Placement new, in contrast, is still relevant because you couldn't implement standard containers without it. – Christian Hackl Jan 16 '18 at 20:48
  • @ChristianHackl, say, you want a container of non-copyable types in C++03. There is simply no way of achieving it. Pre-11 standard actually required types to be copy constructible to be put in the container. With C-style dynamic array you can use placement new on individual elements to achieve the desired functionality. – SergeyA Jan 16 '18 at 20:58
  • @SergeyA: You mean you would first create a dynamic array with `new NonCopyable[n]` and then use placement new over its individual elements? Is that even legal? I have a feeling that I completely misunderstand what you're trying to say. – Christian Hackl Jan 16 '18 at 21:02
  • @ChristianHackl, you would usually create an array of dummy structs and than you placement new on them. I guess one could do it the way you suggested, by calling explicit destructor before placement new over individual elements - but that would be some convoluted code. – SergeyA Jan 16 '18 at 21:15
4

What ... is this?

That is a new-expression. It allocates an object in the free store. More specifically, this expression allocates an array of 12 std::string objects.

What kind of ... initialization is this?

The strings of the array are default-initialized.

And why do this?

The scope of this question is unclear...

  • Why use an array?

Because arrays are the most efficient data structure. They incur zero space overhead and (depending on situation) interact well with processor caching.

  • Why allocate a dynamic array (from the free store)?

Because the size of an automatic array must be known at compile time. The size of a dynamic array does not need to be known until runtime. Of course, your example uses a compile time constant size for the array, so dynamic allocation is not necessary for that reason.

Also because the memory for automatic variables is limited (one to few megabytes on typical desktop systems). As such, large objects such as arrays that contain many objects must be allocated form the free store. An array of 12 strings is not significantly large in relation to the size of memory that is usually available for automatic objects.

Also because dynamic objects are not automatically destroyed at the end of current scope, so their lifetime is more flexible than automatic or static objects. Of course, this is as much a reason to not use dynamic objects: They are not destroyed automatically, and managing their lifetime is difficult and proving the correctness of a program that uses dynamic memory can be very difficult.

  • Why use a new expression to allocate an array

There's typically no reason to do so. The standard library provides a RAII container that handles the lifetime of the dynamically allocated array: std::vector.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • `There's also typically no need to allocate any dynamic objects outside of containers.` what exactly do you mean? – SergeyA Jan 16 '18 at 17:16
  • 1
    @SergeyA that there's typically no need to write `new` or `malloc` in any given program. Such code is ideally written in RAII objects such as STL containers and smart pointers, which are for most purposes provided by the standard library. – eerorika Jan 16 '18 at 17:18
  • This is not what you said, though. 'No need to manually manage memory' (which I agree with) is not the same as 'no need to allocate dynamic objects outside containers' - which I do not agree with. – SergeyA Jan 16 '18 at 18:12
  • @SergeyA could you give me an example of useful dynamic allocation outside of a RAII container? – eerorika Jan 16 '18 at 18:12
  • Any factory-like scenario. – SergeyA Jan 16 '18 at 18:23
  • @SergeyA I would prefer to return an object from a factory, rather than allocating dynamically. But I suppose it's situational of course. – eerorika Jan 16 '18 at 18:45
  • Returning an object from the factory makes factory useless. The whole point of the factory pattern is that the type of the object returned by the factory is not known to the caller code. – SergeyA Jan 16 '18 at 18:52
0

This code is allocating an array of 12 std::string objects and storing the pointer to the first element of the array in the name variable.

std::string* name = new std::string[12];

The new expression allocates an array of 12 std::string objects with dynamic storage duration. Each std::string object in the array is initialized via its default constructor.

The new expression attempts to allocate storage and then attempts to construct and initialize either a single unnamed object, or an unnamed array of objects in the allocated storage. The new-expression returns a prvalue pointer to the constructed object or, if an array of objects was constructed, a pointer to the initial element of the array.

The pointer to the initial element of the array is then stored in name so that you can access the elements of the array using the [] subscript operator.

TypeIA
  • 16,916
  • 1
  • 38
  • 52