-1

I'm reading the answer to When should I use the new keyword in C++?, and Why should C++ programmers minimize use of 'new'?. but I'm a little bit confused.

Is it correct to say that I should use the new keyword whenever I want to create an object whose size could change a lot?

Or do I use new whenever I don't know the size of an object at compile-time?

Take the following examples:

  1. A std::vector which I don't know the size of at compile time, containing user-defined objects. Once initialized, the size never changes.

  2. A std::vector which I know the initial size of, but whose size could change throughout the program.

  3. A user defined object containing std::vector objects, whose sizes all don't change. Other fields also don't change in size, but the sizes are not known at compile-time.

  4. A user defined object whose fields could all change in size

It seems to me that I should use new in case 1 and 2, but not 3 and 4. Although, in 3 and 4, I should use new to allocate memory for the fields inside the user defined object. Is this correct?

Does the usage of new depend on how much the size of an object changes?

If I don't use new, what risks am I taking (such as stackoverflow?)?

In examples 3 and 4, If I don't use new, and I pass this object around, will I be making copies of the object each time I pass it?

If so, and the size of the object is "too big" (for instance, it has many, very large fields), could passing the object possibly cause a stackoverflow, corrupting the data of other objects on the stack?

Finally, when using new, I understand I also have to use delete. However, if a lot of different objects (let's call them A, B, and C) have access to the same pointer (P*), how does calling delete in A affect P* in B and C? I assume it frees up the memory for all of them, such that if I now call P->get_something() in B or C, I would receive a segfault. Then, to prevent a memory leak, as long as something still has access to P*, I should not call delete, but as soon as I'm sure nothing has access to P*, I need to delete it, right?

Community
  • 1
  • 1
Teofrostus
  • 1,296
  • 3
  • 15
  • 26
  • In 98% of the use cases you don't use `new`, asking about the remaining 2% is simply too broad to be answered concisely here. And yes: `new` always needs a `delete` companioned, `new[]` always needs a `delete[]`. – πάντα ῥεῖ Mar 09 '15 at 23:41
  • In C++14, I cannot think of a valid use. It is either `std::make_shared`, `std::make_unique` or `std::vector` instead. – Baum mit Augen Mar 09 '15 at 23:41
  • 1
    @πάνταῥεῖ In 98% of the use cases you *shouldn't* use `new` :) Unfortunately C++ is still taught with `new/delete`, and smart pointers/make_shared(unique) are seen as "advanced" techniques. – vsoftco Mar 09 '15 at 23:42
  • You use new when you have a big object, so copying a single pointer is much faster than copying whole object, also you may want to return a pointer from function, and not copy local object. – codekiddy Mar 09 '15 at 23:44
  • @vsoftco I am kind of glad no one ever taught me C++. :) – Baum mit Augen Mar 09 '15 at 23:44
  • @BaummitAugen yeah me too :) – vsoftco Mar 09 '15 at 23:44
  • 1
    @codekiddy, I hope you've profiled before doing that. – chris Mar 09 '15 at 23:45
  • @vsoftco In my point of view, [it's just the other way round](http://dev-jungle.blogspot.de/2015/02/i-have-dream-im-dreaming-of-so-called-c.html?spref=bl). Using `new`/`delete` is the _advanced_ technique. – πάντα ῥεῖ Mar 09 '15 at 23:47
  • Okay, this doesn't make sense. In the first question I linked, Update 1 specifically says that when he *didn't* use `new`, he corrupted his memory. Yet everyone here is telling me "don't use `new`." Why is this question so bad that everyone jumps on it and starts downvoting it? I'm just learning the language here and, coming from other perspectives (such as Java, where you *always* use `new`) this is very confusing. Ya'll could at least try to help... – Teofrostus Mar 09 '15 at 23:48
  • @Teofrostus C++ is very different from java regarding this (and what `new` actually does). You don't use `new` in c++, you simply don't need it for most of your standard use cases. – πάντα ῥεῖ Mar 09 '15 at 23:51
  • Ok, this seems to build up to something long and interactive. Should we meet in a chat for that? – Baum mit Augen Mar 09 '15 at 23:52
  • @BaummitAugen sure, I'm up for a chat. How do we start one? – Teofrostus Mar 09 '15 at 23:53
  • @Teofrostus, That example that didn't work could use a `std::vector` for free store memory without having to clean up the allocated memory. `new` is useful and all, but there are containers and smart pointers that already have the quirks worked out. – chris Mar 09 '15 at 23:53
  • @Teofrostus I hope I did this right, but here: http://chat.stackoverflow.com/rooms/72622/discussion-on-new-with-teofrostus Hopefully, one of the veterans joins us because they know more than me, but I will be glad to give my two cents. – Baum mit Augen Mar 10 '15 at 00:00
  • There's a lot of talk here about types whose size can change. C++ types have a fixed size, which never changes. In the case of `std::vector`, it manages a dynamic array (using the equivalent of `new` behind the scenes) so you don't have to. There's almost never a need to use `new` in conjunction with that. In general, you never need to use `new` and `delete` unless you have a special need to control object's lifetimes in ways beyond those of the language's more convenient constructs. – Mike Seymour Mar 10 '15 at 00:02

7 Answers7

1

You should use new and allocate from dynamic memory when the quantity of objects is not known at run-time or an object needs a lifetime outside of the function it is declared in.

The issues with many allocations from dynamic memory is fragmentation and performance.

That said, if the object can be reused, allocate one once during initialization and reuse it, then delete the object at program termination. For example, you could create an object once, reload it with input data from the User.

If you know you won't use over a limit of the objects, consider creating an array of the objects once and allocating from the array. This will reduce the fragmentation issue and may increase the performance.

The performance issue with new is that it needs to find a suitable block of memory. Best case this is a simple O(1) access. Worst case, a search must be performed.

So, the preference is to avoid allocation of dynamic memory.

Edit1: Vector
The std::vector will only perform allocations when the reserved space needs to be expanded. If you preallocate the size for 2 objects and push_back a third, the std::vector will reallocate space.

The objective is to reduce the probability that std::vector will reallocate. This can be done by reserving a space that is a little larger than the predicted need. If on average you need to store 6 frames from a camera, you would have std::vector reserve room for 8 frames. This will reduce the number of reallocations by std::vector.

Again, you can reuse a vector. If you are redeclare a vector in a function, you may want to declare it statically and reuse it.

Thomas Matthews
  • 52,985
  • 12
  • 85
  • 144
1

If you call a function that is supposed to return a vector of items, you might opt to return the vector like this:

std::vector<int> GetVecOfObjects()
{
     std::vector<int> objects;

     objects.push_back(1);
     objects.push_back(1);
     objects.push_back(2);
     objects.push_back(3);
     objects.push_back(5);

     return objects;
}

vector<int> myObjects;
myObjects = GetVecOFObjects();

Older versions of c++ would have to make a complete copy of object when they want to put it into myObjects, and then destroy object as the stack is unwound.

This is because objects is created on the stack which will be unwound when GetVecOfObjects() returns. This could be an efficiency problem if you start doing this with vectors containing thousands of elements.

So you could be more efficient, and use a pointer to the vector instead, and use new to create the vector on the heap so that it persists after the function returns:

std::vector<int> *GetVecOfObjects()
{
     std::vector<int> *objects = new std::vector<int>;

     objects.push_back(1);
     objects.push_back(1);
     objects.push_back(2);
     objects.push_back(3);
     objects.push_back(5);

     return objects;
}

vector<int> * myObjects = GetVecOFObjects();
...
delete (myObjects);

Here, all that gets copied is the address of the vector, because objects and myObjects are both pointers. This is fairly easy because the size of the vector doesn't matter, and you can pass this to all sorts of other functions, even other threads, and not worry that the vector will cease to exist if myObjects goes out of scope (though it will cease to exist at the call to delete).

In c++11 and newer, the container classes all implement 'move semantics' using the swap method vector::swap. So when you return objects as a vector that's on the stack, things are much more efficient. Since you're replacing an existing instance of a vector (vector<int> myObjects;) with the one coming from GetVecOfObjects(), they will be 'swapped'. The two objects exchange the references to the data they contain, which can be a very small amount of information. The data that was in myObjects (in this case it was empty, but it doesn't have to be) is now handled by objects, and vice versa. And then as the stack is unwound objects on the stack is cleaned up, thereby getting rid of all the stuff that you clearly weren't going to use any more anyway.

Note that the individual elements in the vector are not on the stack because as another poster indicated, vector will be using new to create the elements.

Arunas
  • 1,162
  • 1
  • 9
  • 16
1

First all let me ask you to go through basics of heap and stack memory. Go through Why should C++ programmers minimize use of 'new'? . Then go through this below comparison between memory allocation in C and C++, You will get full clarity.
Explanation:

Using C++ new operator: new is an operator used to allocate memory from the heap.

  • In first step new operator allocates the storage of size (sizeof type) on the heap by calling operator new(). operator new() by taking the size_t as parameter and returns the pointer of newly allocated memory.
  • In second step new operator initialize that memory by calling constructor of passed type/class.

Using new/delete normally:

A* a = new A();

delete a;

Using C malloc library function: The same above C++ variant can be done in C using the malloc C library call which in turn calls brk() system call in kernel space to initialize the memory but never calls the constructor of the class. To make use of malloc as an replacement to the above c++ variant we can do it as below.

Calling the constructor/destructor explicitly ("placement new"):

A* a = (A*)malloc(sizeof(A));
new (a) A();

a->~A();
free(a);
Helping Bean
  • 139
  • 7
0

for std::vector dont use new. std::vector itself uses new internally as it needs to grow

The only time you need to new a vector is if you need a variable number of vectors. Then you could have a vector of vectors

pm100
  • 32,399
  • 19
  • 69
  • 124
0
  1. A std::vector which I don't know the size of at compile time, containing user-defined objects. Once initialized, the size never changes.

You use the std::vector constructor(2) or the std::vector::resize() function to set the vector's initial size.

  1. A std::vector which I know the initial size of, but whose size could change throughout the program.

Same as for 1., and you use e.g. std::vector::push_back() to add more elements.

  1. A user defined object containing std::vector objects, whose sizes all don't change. Other fields also don't change in size, but the sizes are not known at compile-time.

Same as 1., initialize them with the correct constructor attributes.

  1. A user defined object whose fields could all change in size

Same as 1. and 2.

πάντα ῥεῖ
  • 83,259
  • 13
  • 96
  • 175
0

First of all, the size of objects don't change, ever. This includes std::vector objects. Now this is perhaps confusing, since std::vector has a size() member function, which can in fact return different values over its lifetime. But that is not the size of the object, it is the number of elements that the vector manages. But these elements are not in the vector object itself, they are referred to by a pointer. So they don't affect the size of the actual vector object, no matter how many there are.

With that in mind, in addressing your cases, I'll assume when you say size, you mean number of elements, because the alternative doesn't make any sense.

A std::vector which I don't know the size of at compile time, containing user-defined objects. Once initialized, the size never changes.

std::vector handles the allocation and deallocation of its elements. Don't use new.

A std::vector which I know the initial size of, but whose size could change throughout the program.

std::vector handles the allocation and deallocation of its elements. Don't use new.

A user defined object containing std::vector objects, whose sizes all don't change. Other fields also don't change in size, but the sizes are not known at compile-time.

The answer depends upon what those other fields are. Hopefully, they are well written classes, like std::vector, which also take care of allocation and deallocation of any memory they use. In which case, don't use new. If they aren't well written classes which handle their own allocation, then I would suggest you reconsider your choice to use them.

A user defined object whose fields could all change in size

Same as above.

Benjamin Lindley
  • 95,516
  • 8
  • 172
  • 256
0

In short:

  • Don't use new at all.

Longer:

  • Learn, what the difference between heap and stack is.
  • Learn about smartpointers and especially std::make_unique and std::make_shared
  • Understand how std::vector works internally
  • If you absolutely have to use new, don't forget to call delete at some point in time.
MikeMB
  • 17,569
  • 7
  • 51
  • 93