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.