Why use new?

S

saneman

In the below code I make 2 instances of the class Bob. The first
instance does not use new (automatic allocation?) and the second
instance is used with new (dynamic allocation?)


#include<iostream>

class Bob {
public:
Bob(int a): n(a) {}

int getn() {
return n;
}

private:
int n;

};

int main() {
Bob b1(22);
printf("n = %d\n", b1.getn());

Bob* b2 = new Bob(88);
printf("n = %d\n", b2->getn());

return 0;
}


But when are there any reason to use new?

And will the b2 pointer automatically be deallocated when main returns?
 
V

Victor Bazarov

saneman said:
In the below code I make 2 instances of the class Bob. The first
instance does not use new (automatic allocation?) and the second
instance is used with new (dynamic allocation?)


#include<iostream>

class Bob {
public:
Bob(int a): n(a) {}

int getn() {
return n;
}

private:
int n;

};

int main() {
Bob b1(22);
printf("n = %d\n", b1.getn());

Bob* b2 = new Bob(88);
printf("n = %d\n", b2->getn());

return 0;
}


But when are there any reason to use new?

What does your favourite C++ book say about the use of dynamic memory?
Read up on lifetime of objects. To hint: there are three "lifetimes"
(they are called "storage duration" in C++): automatic, static, and
dynamic.
And will the b2 pointer automatically be deallocated when main
returns?

No, it will not. It may or may not be deallocated by the hosting
environment when the program finishes. Most modern operating systems
do deallocate all memory used by the process when the process closes
and returns control to the OS.

V
 
S

sean_in_raleigh

But when are there any reason to use new?

There are a variety of situations, but the most
common one is when you need the object to outlive
the current function. E.g.:

Date* createDateOnStack() { Date d; return &d; } //
bug!
Date* createDateOnHeap() { Date *d = new Date(); return d; } // OK

And will the b2 pointer automatically be deallocated when main returns?

Yes, but not the way you want: the *pointer* will be deallocated
since it lives on the stack next to the b1 object, but the
*object it points to* will not be deallocated, since it lives
in the heap that "new" allocates from.

A good rule of thumb is to use automatic allocation when
you can, and explicit allocation when you must.

Sean
 
S

saneman

Victor said:
What does your favourite C++ book say about the use of dynamic memory?
Read up on lifetime of objects. To hint: there are three "lifetimes"
(they are called "storage duration" in C++): automatic, static, and
dynamic.


No, it will not. It may or may not be deallocated by the hosting
environment when the program finishes. Most modern operating systems
do deallocate all memory used by the process when the process closes
and returns control to the OS.

V

Ok I am a bit confused if I need to implement a destructor. Since I
don't use new in the class Bob is it enough to just do:

delete(b2);

as the last thing in the main function? Can't see what good any
destructor would do since it cannot destruct itself.
 
J

jason.cipriani

But when are there any reason to use new?


Depends on the situation, of course. One example is when you want to
create and refer to derived classes by their base, perhaps in an STL
container, e.g.:


class Base { };

class D1 : public Base { };

class D2 : public Base { };

std::vector<Base *> things;

void f () {
things.push_back(new D1);
things.push_back(new D2);
}


This is especially true when the derived classes are instantiated at
runtime in response to, say, user interaction (i.e. you don't know
what you are going to need ahead of time when you are writing your
program).

Jason
 
V

Victor Bazarov

saneman said:
[..]
Ok I am a bit confused if I need to implement a destructor.

Most likely not. Read about "the Rule of Three".
Since I
don't use new in the class Bob is it enough to just do:

delete(b2);

Parentheses are superfluous.
as the last thing in the main function? Can't see what good any
destructor would do since it cannot destruct itself.

Presence of the destructor and the need to free the memory are
orthogonal.

V
 
J

James Kanze

In the below code I make 2 instances of the class Bob. The first
instance does not use new (automatic allocation?) and the second
instance is used with new (dynamic allocation?)

class Bob {
public:
Bob(int a): n(a) {}
int getn() {
return n;
}
private:
int n;
};
int main() {
Bob b1(22);
printf("n = %d\n", b1.getn());
Bob* b2 = new Bob(88);
printf("n = %d\n", b2->getn());
return 0;
}
But when are there any reason to use new?

Lots. Most of the time, you use new because you need an
explicit lifetime for the object. You create it in some low
level function, in response to an external event, and you delete
it in some other low level function, in response to some other
external event.

Other reasons might be because you won't know the actual type
until runtime, or the object is part of a dynamic, variably
sized data structure.
And will the b2 pointer automatically be deallocated when main
returns?

Of course not. That would sort of defeat the purpose of dynamic
allocation, wouldn't it?

(Actually, in the case of main, the memory will be deallocated
when you return from the function. Not immediately, but
returning from main means terminating the program, and on
program terminiation, the memory will all be deallocated. But
in general, the purpose of using new is precisely to ensure that
the object lives until you want to explicitly terminate its
lifetime.)
 
J

James Kanze

saneman said:
[..]
Ok I am a bit confused if I need to implement a destructor.
Most likely not. Read about "the Rule of Three".
Parentheses are superfluous.
Presence of the destructor and the need to free the memory are
orthogonal.

So you're using the Boehm collector too:).

Seriously, I think your statement can easily be misinterpreted.
One major reason to provide a user defined destructor is to free
memory. Memory allocated and managed within the class, though,
not the basic memory in which the class itself resides. (Which
I'm sure is what you meant.)
 
P

Paul Brettschneider

James said:
Lots. Most of the time, you use new because you need an
explicit lifetime for the object. You create it in some low
level function, in response to an external event, and you delete
it in some other low level function, in response to some other
external event.

I guess with the advent of containers with non-copyable elements, more and
more of those new() calls will be hidden in std::container::insert() calls
and the like.
 
P

peter koch

(Actually, in the case of main, the memory will be deallocated
when you return from the function.  Not immediately, but
returning from main means terminating the program, and on
program terminiation, the memory will all be deallocated.  But
in general, the purpose of using new is precisely to ensure that
the object lives until you want to explicitly terminate its
lifetime.)

When you return from main, there is not really much you can tell from
a C++ point of view. At least, thats what I was told by some
knowledgeable person in here some time ago ;-)

/Peter
 
F

Fred Zwarts

peter koch said:
When you return from main, there is not really much you can tell from
a C++ point of view. At least, thats what I was told by some
knowledgeable person in here some time ago ;-)

Well, you know that at least the static objects are deleted after return from main.
So, destructors may be called, etc.
For dynamically created object this is not defined.
 
J

James Kanze

Paul said:
James Kanze wrote:

[...]
I guess with the advent of containers with non-copyable
elements, more and more of those new() calls will be hidden in
std::container::insert() calls and the like.

I'm not sure what containers you're talking about, but I very
much doubt that any of the calls to new would be found in their
insert() functions.

In the scenario I described (a very, very frequent one for
servers, GUI's and probably a number of other applications), the
new is in response to an external event, as is the delete.
Containers don't repond to external events.
 
J

James Kanze

When you return from main, there is not really much you can
tell from a C++ point of view. At least, thats what I was told
by some knowledgeable person in here some time ago ;-)

Once you've finished calling the destructors of static objects,
you leave the world defined by the language. And return to the
one from which you invoked the application. And it's certainly
possible to leak resources in such cases. But in a hosted
environment, it seems reasonable to expect most resources
(including memory) to be freed unless the program specifically
requested otherwise. As a quality of implementation issue, if
nothing else. And of course, in a non-hosted environment, there
may not even be a main.
 
P

Paul Brettschneider

James said:
Paul said:
James Kanze wrote:
[...]
But when are there any reason to use new?
Lots. Most of the time, you use new because you need an
explicit lifetime for the object. You create it in some low
level function, in response to an external event, and you delete
it in some other low level function, in response to some other
external event.
I guess with the advent of containers with non-copyable
elements, more and more of those new() calls will be hidden in
std::container::insert() calls and the like.

I'm not sure what containers you're talking about, but I very
much doubt that any of the calls to new would be found in their
insert() functions.

In the scenario I described (a very, very frequent one for
servers, GUI's and probably a number of other applications), the
new is in response to an external event, as is the delete.
Containers don't repond to external events.

My idea was that you will have code like this (totally made up this moment):

Handle open_window(const std::string &title)
{
extern std::map<Handle, Window> Windows;
Handle h(Windows); // Generates unique handle
Window &w = Windows[h];

w.set_title(title)
return h;
}

Here the new() is hidden in operator[] of std::map. IMHO new and delete are
low-level functions (or call them operators) and application developers
should not have to care too much about them. But maybe I'm just silly?
 
I

Ian Collins

Paul said:
James said:
Paul Brettschneider wrote:
I'm not sure what containers you're talking about, but I very
much doubt that any of the calls to new would be found in their
insert() functions.

In the scenario I described (a very, very frequent one for
servers, GUI's and probably a number of other applications), the
new is in response to an external event, as is the delete.
Containers don't repond to external events.

My idea was that you will have code like this (totally made up this moment):

Handle open_window(const std::string &title)
{
extern std::map<Handle, Window> Windows;
Handle h(Windows); // Generates unique handle
Window &w = Windows[h];

w.set_title(title)
return h;
}

Here the new() is hidden in operator[] of std::map. IMHO new and delete are
low-level functions (or call them operators) and application developers
should not have to care too much about them. But maybe I'm just silly?

Where? How is the above any different from

std::map<unsigned,std::string> strings;

std::string& s = strings[42];

There may well be a call to new, but it will be within the constructor
of std::string.
 
P

Paul Brettschneider

Ian said:
Paul said:
James said:
Paul Brettschneider wrote:
I guess with the advent of containers with non-copyable
elements, more and more of those new() calls will be hidden in
std::container::insert() calls and the like.
I'm not sure what containers you're talking about, but I very
much doubt that any of the calls to new would be found in their
insert() functions.

In the scenario I described (a very, very frequent one for
servers, GUI's and probably a number of other applications), the
new is in response to an external event, as is the delete.
Containers don't repond to external events.

My idea was that you will have code like this (totally made up this
moment):

Handle open_window(const std::string &title)
{
extern std::map<Handle, Window> Windows;
Handle h(Windows); // Generates unique handle
Window &w = Windows[h];

w.set_title(title)
return h;
}

Here the new() is hidden in operator[] of std::map. IMHO new and delete
are low-level functions (or call them operators) and application
developers should not have to care too much about them. But maybe I'm
just silly?

Where? How is the above any different from

It's the same thing. :p
std::map<unsigned,std::string> strings;

std::string& s = strings[42];

There may well be a call to new, but it will be within the constructor
of std::string.

James' point was that new is used for handling objects with non-scoped
lifetime (I think). I believe that often you will just create those objects
in containers, which will do the new/delete for you. Nowadays this is often
not doable because such objects (windows/files/whatever) are non-copyable.
 
I

Ian Collins

Paul said:
Ian Collins wrote:

It's the same thing. :p
std::map<unsigned,std::string> strings;

std::string& s = strings[42];

There may well be a call to new, but it will be within the constructor
of std::string.

James' point was that new is used for handling objects with non-scoped
lifetime (I think). I believe that often you will just create those objects
in containers, which will do the new/delete for you. Nowadays this is often
not doable because such objects (windows/files/whatever) are non-copyable.

OK, I think I can see where you are coming from now. Currently std::map
is the only container I know than creates objects "on demand". The way
forward as I see it follows the pattern of std::string: the objects
stored in the container are some form of smart pointer, with their own
copy semantics and lifetime management.
 
J

James Kanze

James said:
Paul said:
James Kanze wrote:
[...]
But when are there any reason to use new?
Lots. Most of the time, you use new because you need an
explicit lifetime for the object. You create it in some low
level function, in response to an external event, and you delete
it in some other low level function, in response to some other
external event.
I guess with the advent of containers with non-copyable
elements, more and more of those new() calls will be hidden in
std::container::insert() calls and the like.
I'm not sure what containers you're talking about, but I very
much doubt that any of the calls to new would be found in their
insert() functions.
In the scenario I described (a very, very frequent one for
servers, GUI's and probably a number of other applications), the
new is in response to an external event, as is the delete.
Containers don't repond to external events.
My idea was that you will have code like this (totally made up
this moment):
Handle open_window(const std::string &title)
{
extern std::map<Handle, Window> Windows;
Handle h(Windows); // Generates unique handle
Window &w = Windows[h];
w.set_title(title)
return h;
}

Which, of course, typically won't work, because classes like
Window typically don't support copy. Also, they are
polymorphic, so the actual type will be something derived from
Window. And of course, the standard containers don't use the
new operator either, since they separate allocation and
initialization.

Generally speaking: if an object has an explicit lifetime, it
almost always also has identity, and so won't support copy, and
can't be put in a standard container. And the standard
containers don't support polymorphism either. There are cases
where it might be appropriate to have a container own an object,
i.e. by containing it via some sort of smart pointer, but they
are fairly rare. Most of the time, the container is at the
service of some higher level concept, and it is the
implementation of the higher level concept (often the object
itself) which takes charge of managing object lifetime.
Here the new() is hidden in operator[] of std::map. IMHO new
and delete are low-level functions (or call them operators)
and application developers should not have to care too much
about them. But maybe I'm just silly?

Maybe. In the applications I work on, or have worked on (large
scale servers, mostly, but also one GUI framework), the
application had to deal with arbitrary lifetimes of entity
objects, and with polymorphic objects, whereas the lower levels
mainly dealt with value objects, or just shuffled pointers
around, and used templates more than dynamic allocation. If the
lifetime of an object is part of the application design, then
the application programmers will have to deal with it. And if
the choice of which polymorphic type to use is determined by
the application, application programmers will have to deal with
it. In my experience, the higher you go in the abstraction
levels, the more the new operator becomes relevant. (There are
some low level structures where it would be relevant as well,
things like graphs and such. I've not had to deal with them
much myself, however.)
 
J

James Kanze

OK, I think I can see where you are coming from now.
Currently std::map is the only container I know than creates
objects "on demand". The way forward as I see it follows the
pattern of std::string: the objects stored in the container
are some form of smart pointer, with their own copy semantics
and lifetime management.

But in most cases, isn't this more or less obfuscation.
Consider something like:

void
deleteMO( DN const& id )
{
objectMap.erase( id ) ;
// triggers destruction of object
// via smart pointer, destructor
// takes care of notifying other
// observers.
}

and

void
deleteMO( DN const& id )
{
objectMap[ id ]->destroy() ;
// will call delete this, and the
// destructor will remove the
// object from the map, at the same
// time it notifies other
// observers.
}

Or even more likely, in the object itself:

void
DerivedMOType::processEvent(
EventType const& event )
{
// ...
if ( eventRequestsDestruction( event ) ) {
objectMap.erase( myId ) ;
// As above---this will result in
// the destructor being called
// before the return from the erase
// function!!!
}
}

vs.

void
DerivedMOType::processEvent(
EventType const& event )
{
// ...
if ( eventRequestsDestruction( event ) ) {
delete this ; // nice and visible, so I clearly
// see that I'd best not do
// anything else here.
}
}

Most of the time, for entity objects, destruction is the result
of some external event. You can design the system so that it
happens indirectly, e.g. as a result of removing the object from
the objectMap used to find it, or some such, but most of the
time, I would argue that the code is clearer if you do an
explicit delete, and the destructor of the object removes it
from the objectMap at the same time it notifies all other
interested parties (since the object is often in relationship
with other objects, which have to be informed of its demise).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,176
Messages
2,570,947
Members
47,498
Latest member
log5Sshell/alfa5

Latest Threads

Top