Deleting objects obtained from a STL library

A

Aguilar, James

Hey guys. A new question:

I want to use an STL libarary to hold a bunch of objects I create.
Actually, it will hold references to the objects, but that's beside the
point, for the most part. Here's the question: I want to be able to change
the references (including deleting them). Is there any way to do that
besides using pointers rather than references for the STL library? I'd also
prefer to avoid using const_cast, if it is indeed avoidable.

Thanks much.
 
R

Rob Williscroft

Aguilar, James wrote in in
comp.lang.c++:
Hey guys. A new question:

I want to use an STL libarary to hold a bunch of objects I create.
Actually, it will hold references to the objects, but that's beside
the point, for the most part. Here's the question: I want to be able
to change the references (including deleting them). Is there any way
to do that besides using pointers rather than references for the STL
library? I'd also prefer to avoid using const_cast, if it is indeed
avoidable.

http://www.boost.org/libs/smart_ptr/shared_ptr.htm

And *don't* use const_cast, if you feel tempted go back and
redesign until the *itch* goes away.

Rob.
 
A

Aguilar, James

Aguilar said:
Hey guys. A new question:

I want to use an STL libarary to hold a bunch of objects I create.
Actually, it will hold references to the objects, but that's beside the
point, for the most part. Here's the question: I want to be able to change
the references (including deleting them). Is there any way to do that
besides using pointers rather than references for the STL library? I'd also
prefer to avoid using const_cast, if it is indeed avoidable.

Thanks much.

I think I might have misunderstood my own question. First, please clarify
something for me:

Are the objects in the container the same objects as the ones that I used to
fill the container? Are they references to those objects, or are they
copies of those objects? How did the container know how to make the copies?
Are they just shallow copies of the original objects (i.e. all pointers are
the same, all other members were copied completely)?

Secondly, suppose I have a function. There is a type called Object which I
use here:

Object& fun1()
{
Object a;
return a;
}

is not legal but

Object fun1()
{
Object a;
return a;
}

is. I think I understand why. However, let me ask you this: is this code
going to be inefficient if "Object" is ten kilobytes in size? Is what's
actually happening in the second example is that the entire object is being
copied and returned? Lastly, if this is so, can this overhead be avoided by
only passing ints and assigning all medium or large sized objects to the
free store?

Lastly, is there anything I can do with references that I can't do with
pointers? Is there anything that is especially inelegant with pointers that
references accomplish well? For instance, I had a class that we going to
have a vector (that was itself a vector of vectors) member earlier.
However, there are two ways to do it. One is to tell the class that all it
has is a pointer to a vector, and one is to make the vector actually a
member of the class. I found that with a pointer to a vector, accessing the
vector would look ugly indeed:

(*(*grid)[10])[25]->foo(); /*Isn't there any way to at least make this look
better? It does the same thing as the second
example */

is the same as

grid[10][25].foo();

only the second uses the actual objects or references to them, and the first
uses pointers. However, my experience in Java (which is the language I
began working on before I began teaching myself C++) tells me that passing
pointers around is more efficient than passing objects around (in the event
that large objects need to be communicated between different parts of the
program). I'm also used to the convenience of never touching an actual
object, but always working with pointers. I have this natural, builtin
aversion to copying objects unless you are actually conceptually going to be
using a copy of them. For instance, if my suspicions are correct and the
first example in which I pass out an "Object" named a is correct and the
method is copying a to return it, I would rather use the free store.
There's no reason why the object should have to be constructed twice in an
example like that.

I guess my question is, on which side should I err: using the free store a
lot and using pointers a lot, or using references a lot and perhaps paying
overhead when I return large objects from methods?
 
D

David Hilsee

Aguilar said:
I think I might have misunderstood my own question. First, please clarify
something for me:

Are the objects in the container the same objects as the ones that I used to
fill the container? Are they references to those objects, or are they
copies of those objects? How did the container know how to make the copies?
Are they just shallow copies of the original objects (i.e. all pointers are
the same, all other members were copied completely)?

The objects stored inside an STL container are copies. For example:

MyClass c;
std::vector<MyClass> v;
v.push_back(c);

The vector now contains one instance of MyClass that was copied from c
(using the copy constructor). If the copy constructor is defined as a
"shallow" copy, then the copy made is "shallow".
Secondly, suppose I have a function. There is a type called Object which I
use here:

Object& fun1()
{
Object a;
return a;
}

is not legal but

Object fun1()
{
Object a;
return a;
}

is. I think I understand why. However, let me ask you this: is this code
going to be inefficient if "Object" is ten kilobytes in size? Is what's
actually happening in the second example is that the entire object is being
copied and returned? Lastly, if this is so, can this overhead be avoided by
only passing ints and assigning all medium or large sized objects to the
free store?

Questions about efficiency are hard to answer without measurements. There
are a few reasonable guidelines, but it's usually best to run some tests to
determine how expensive an operation is. However, I will say that one
rarely allocates something using dynamic allocation because it is more
efficient that way. I could see how there might be other concerns, though,
like stack space.

Also, it is possible that your compiler would use NRVO (named return value
optimization) to avoid copying objects in certain cases, so it's hard to say
if there is a copy made or not.
Lastly, is there anything I can do with references that I can't do with
pointers? Is there anything that is especially inelegant with pointers that
references accomplish well? For instance, I had a class that we going to
have a vector (that was itself a vector of vectors) member earlier.
However, there are two ways to do it. One is to tell the class that all it
has is a pointer to a vector, and one is to make the vector actually a
member of the class. I found that with a pointer to a vector, accessing the
vector would look ugly indeed:

Pointers are useful because their values may change. A single pointer, over
time, may point to different locations, or nothing at all (usually signified
with a null pointer). References, however, lack this ability, and that
makes them simpler when such functionality is not required. Also,
references cannot be null. The simplicity is the main reason why references
and not pointers are usually used to pass an object to a function without
creating a copy.
(*(*grid)[10])[25]->foo(); /*Isn't there any way to at least make this look
better? It does the same thing as the second
example */

is the same as

grid[10][25].foo();

only the second uses the actual objects or references to them, and the first
uses pointers. However, my experience in Java (which is the language I
began working on before I began teaching myself C++) tells me that passing
pointers around is more efficient than passing objects around (in the event
that large objects need to be communicated between different parts of the
program). I'm also used to the convenience of never touching an actual
object, but always working with pointers. I have this natural, builtin
aversion to copying objects unless you are actually conceptually going to be
using a copy of them. For instance, if my suspicions are correct and the
first example in which I pass out an "Object" named a is correct and the
method is copying a to return it, I would rather use the free store.
There's no reason why the object should have to be constructed twice in an
example like that.

I guess my question is, on which side should I err: using the free store a
lot and using pointers a lot, or using references a lot and perhaps paying
overhead when I return large objects from methods?

One thing to keep in mind is that when an object is dynamically allocated,
it is typically the memory allocation itself that is the most expensive part
of the ordeal. However, if the object is a big, complex object that is
expensive to copy, then it may make sense to avoid copying it. That expense
is not usually measured in terms of bytes, but in terms of the time and
possibly extra memory it takes to execute the copy constructor (It's usually
not hard to copy a reasonable number of bytes from one location to another).
There is no one, true answer. In general, C++ programmers avoid using
dynamic allocation unless it is called for, so don't make dynamic allocation
the "default" method for allocation objects in your programs. If you do
that, C++ programmers will be able to smell the Java a mile away. ;-)

For objects that are expensive to copy, it is sometimes possible to
implement a "swap" method to avoid copying them. For example:

void foo(std::vector<int>& out) {
std::vector<int> v(20);
// fill in v
v.swap( out );
}

The std::vector::swap method doesn't perform an expensive copy operation and
instead quickly exchanges the vector's contents with the vector passed
(think internal pointer, etc value swapping).

If you do find yourself passing pointers to objects around, consider using
smart pointers, like boost::shared_ptr, because it can help protect your
code from memory leaks.
 
F

fabio de francesco

Hello,

David Hilsee said:
The objects stored inside an STL container are copies. For example:

MyClass c;
std::vector<MyClass> v;
v.push_back(c);

The vector now contains one instance of MyClass that was copied from c
(using the copy constructor).

does it mean that 2*sizeof(c) memory space is now occupied?
If the copy constructor is defined as a
"shallow" copy, then the copy made is "shallow".

What is a "shallow" copy?

Thank you,

Fabio.
 
D

Daniel T.

Aguilar said:
Are the objects in the container the same objects as the ones that I used to
fill the container?

No, stl containers make copies. For example:

void foo( vector<int>& vec ) {
int i = 5;
vec.push_back( i );
}

The fact that 'i' goes out of scope at the end of the function isn't a
problem because 'i' isn't in the vector, a copy of 'i' is.

How did the container know how to make the copies?

The container uses the copy constructor, if no copy c_tor is provided
then the compiler will make one, if the copy c_tor is disabled (by
making it private and not implementing it) then the object type cannot
be held in an stl container.

Are they just shallow copies of the original objects (i.e. all pointers are
the same, all other members were copied completely)?

If the copy c_tor makes shallow copies then they are just shallow copies.

Secondly, suppose I have a function. There is a type called Object which I
use here:

Object& fun1()
{
Object a;
return a;
}

is not legal but

Object fun1()
{
Object a;
return a;
}

is. I think I understand why. However, let me ask you this: is this code
going to be inefficient if "Object" is ten kilobytes in size?

Possibly, you won't know until you measure.

Is what's
actually happening in the second example is that the entire object is being
copied and returned?
Possibly.


Lastly, if this is so, can this overhead be avoided by
only passing ints and assigning all medium or large sized objects to the
free store?

The usual way to avoid this is to pass in an object by reference and let
the function modify it. As in:

Object& fun1( Object& a ) {
// do stuff to 'a'
return a;
}

But again, this usually isn't necessary. Measure first.

Lastly, is there anything I can do with references that I can't do with
pointers?
No.


Is there anything that is especially inelegant with pointers that
references accomplish well?

Yes, operator overloading for example.

For instance, I had a class that we going to
have a vector (that was itself a vector of vectors) member earlier.

Don't use vector of vectors. Write a Matrix class instead. (See the FAQ
on this.)

However, there are two ways to do it. One is to tell the class that all it
has is a pointer to a vector, and one is to make the vector actually a
member of the class.

Make the vector a member of the class. There is almost no reason to
dynamically allocate a standard container (I say 'almost' simply because
I'm hedging, I can think of no reason to dynamically allocate a
container.)

I found that with a pointer to a vector, accessing the
vector would look ugly indeed:

(*(*grid)[10])[25]->foo(); /*Isn't there any way to at least make this look
better? It does the same thing as the second
example */

is the same as

grid[10][25].foo();

only the second uses the actual objects or references to them, and the first
uses pointers. However, my experience in Java (which is the language I
began working on before I began teaching myself C++) tells me that passing
pointers around is more efficient than passing objects around (in the event
that large objects need to be communicated between different parts of the
program).

It may, or may not, be more efficient. You won't know until you measure.

I'm also used to the convenience of never touching an actual
object, but always working with pointers. I have this natural, builtin
aversion to copying objects unless you are actually conceptually going to be
using a copy of them. For instance, if my suspicions are correct and the
first example in which I pass out an "Object" named a is correct and the
method is copying a to return it, I would rather use the free store.
There's no reason why the object should have to be constructed twice in an
example like that.

I guess my question is, on which side should I err: using the free store a
lot and using pointers a lot, or using references a lot and perhaps paying
overhead when I return large objects from methods?

Don't do either. Err on the side of using objects a lot, switch over to
using references and pointers only when the language requires it, or
measurement shows its necessary.
 
J

Jeff Flinn

Aguilar said:
Are the objects in the container the same objects as the ones that I used to
fill the container? Are they references to those objects, or are they

No, STL containers hold copies of the values you inserted into them. You can
not insert references into a container.
copies of those objects? How did the container know how to make the
copies?

They use the copy constructor for the type passed.
Are they just shallow copies of the original objects (i.e. all pointers are
the same, all other members were copied completely)?

That's up to you when you implement the copy constructor. If you don't
supply one, the compiler provided default is a member wise copy. ie: invokes
the copy constructor of each memeber.
Secondly, suppose I have a function. There is a type called Object which I
use here:

Object& fun1()
{
Object a;
return a;
}

is not legal but

Because upon exit of fun1 a is destroyed, so you end up with a reference to
a destroyed object.
Object fun1()
{
Object a;
return a;
}

is. I think I understand why. However, let me ask you this: is this code

You end up with an Object that is a copy of 'a'.
going to be inefficient if "Object" is ten kilobytes in size? Is what's
actually happening in the second example is that the entire object is being
copied and returned? Lastly, if this is so, can this overhead be avoided
by

Maybe so, maybe not. Many compilers provide RVO and/or NRVO ( named return
value optimization ). Which would elide the copy. Hence, the rule - avoid
premature optimization.
only passing ints and assigning all medium or large sized objects to the
free store?

As another poster suggested, use boost::shared_ptr:

typedef boost::shared_ptr said:
tObjPtr fun1()
{
return tObjPtr( new Object );
}

Lastly, is there anything I can do with references that I can't do with
pointers? Is there anything that is especially inelegant with pointers
that

References can't be reseated, and must be initialized.

[...]
I guess my question is, on which side should I err: using the free store a
lot and using pointers a lot, or using references a lot and perhaps paying
overhead when I return large objects from methods?

You should really get a good C++ book and study the FAQ.

Jeff F
 
D

David Hilsee

fabio de francesco said:
Hello,

"David Hilsee" <[email protected]> wrote in message

does it mean that 2*sizeof(c) memory space is now occupied?

At a minimum. If by "occupied" you mean "allocated" then there could easily
be more than that, because the std::vector object is probably holding on to
a single block of memory that could potentially hold more instances of
MyClass so it can have more efficient behavior if it is asked to hold more
instances.
What is a "shallow" copy?

Not a deep copy. ;-) It is typically used to mean that the copy might leave
some data as shared between the two objects. For example, if you create a
copy of a tree object and the data stored in the nodes is shared between the
two trees, then that could be called a "shallow" copy, because it didn't
copy everything stored in the tree.
 
F

fabio de francesco

David Hilsee said:
At a minimum. If by "occupied" you mean "allocated" then there could easily
be more than that, because the std::vector object is probably holding on to
a single block of memory that could potentially hold more instances of
MyClass so it can have more efficient behavior if it is asked to hold more
instances.

Thank you.
So, in the example given, and in order to avoid the original "c"
object to be kept around, should we delete it? And how? By an explicit
call to the destructor? Please let me know.

Fabio De Francesco.
 
D

David Hilsee

fabio de francesco said:
"David Hilsee" <[email protected]> wrote in message

Thank you.
So, in the example given, and in order to avoid the original "c"
object to be kept around, should we delete it? And how? By an explicit
call to the destructor? Please let me know.

The c object will be destroyed when it goes out of scope. No explicit call
to anything is required. Calling the destructor explicitly will only cause
the destructor to execute and it will not cause the storage for the object
itself to be released. Also, it would probably cause problems because the
destructor would be invoked again when the c object goes out of scope.
 

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
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top