views:

286

answers:

5

I just started learning about pointers in C++, and I'm not very sure on when to use pointers, and when to use actual objects.

For example, in one of my assignments we have to construct a gPolyline class, where each point is defined by a gVector. Right now my variables for the gPolyline class looks like this:

private:
vector<gVector3*> points;

If I had vector< gVector3 > points instead, what difference would it make? Also, is there a general rule of thumb for when to use pointers? Thanks in advance!

A: 

You can use pointers or objects - it's really the same at the end of the day.

If you have a pointer, you'll need to allocate space for the actual object (then point to it) any way. At the end of the day, if you have a million objects regardless of whether you are storing pointers or the objects themselves, you'll have the space for a million objects allocated in the memory.

When to use pointers instead? If you need to pass the objects themselves around, modify individual elements after they are in the data structure without having to retrieve them each and every time, or if you're using a custom memory manager to manage the allocation, deallocation, and cleanup of the objects.

Putting the objects themselves in the STL structure is easier and simpler. It requires less * and -> operators which you may find to be difficult to comprehend. Certain STL objects would need to have the objects themselves present instead of pointers in their default format (i.e. hashtables that need to hash the entry - and you want to hash the object, not the pointer to it) but you can always work around that by overriding functions, etc.

Bottom line: use pointers when it makes sense to. Use objects otherwise.

Computer Guru
Still not a good idea to use pointers here. Better would be to use the STL's iterators and iterate over collections that way. If you're concerned about object space, you're better off using some form of `shared_ptr`. Finally, using raw pointers breaks every one of the standard algorithms with remove semantics, such as `std::remove`, `std::remove_if`, `std::unique`, `std::replace`, `std::replace_if`, etc.
Billy ONeal
+1  A: 

Pointers are generally to be avoided in modern C++. The primary purpose for pointers nowadays revolves around the fact that pointers can be polymorphic, whereas explicit objects are not.

When you need polymorphism nowadays though it's better to use a smart pointer class -- such as std::shared_ptr (if your compiler supports C++0x extensions), std::tr1::shared_ptr (if your compiler doesn't support C++0x but does support TR1) or boost::shared_ptr.

Billy ONeal
I don't know what you mean by "modern C++" but on many huge projects that I've worked on, I've had to migrate code from `STL_Struct<object>` to `STL_Struct<object *>` :)Sometimes you *need* a pointer to the object instead of the object itself for reasons I clarify in my above answer... But I'll grant you that usually there is no need for pointers.
Computer Guru
By "Modern C++" I mean the C++03 standard, or ANSI/ISO standardized C++. Several older compilers do not completely implement the standard, and pointers are needed to patch over such compilers' inconsistencies.
Billy ONeal
@Neil - Fixed -- Also fixed your name...
Billy ONeal
A: 

Normally you use objects.
Its easier to eat an apple than an apple on a stick (OK 2 meter stick because I like candy apples).

In this case just make it a vector<gVector3>

If you had a vector<g3Vector*> this implies that you are dynamically allocating new objects of g3Vector (using the new operator). If so then you need to call delete on these pointers at some point and std::Vector is not designed to do that.

But every rule is an exception.

If g3Vector is a huge object that costs a lot to copy (hard to tell read your documentation) then it may be more effecient to store as a pointer. But in this case I would use the boost::ptr_vector<g3Vector> as this automatically manages the life span of the object.

Martin York
@Billy: Go read about boost::ptr_vector.
Martin York
@Martin -- I'm sorry -- that comment was intended for another post.
Billy ONeal
+2  A: 

The general rule of thumb is to use pointers when you need to, and values or references when you can.

If you use vector<gVector3> inserting elements will make copies of these elements and the elements will not be connected any more to the item you inserted. When you store pointers, the vector just refers to the object you inserted.

So if you want several vectors to share the same elements, so that changes in the element are reflected in all the vectors, you need the vectors to contain pointers. If you don't need such functionality storing values is usually better, for example it saves you from worrying about when to delete all these pointed to objects.

sth
A: 

Generally, it's a good idea to use pointers when you have to, but references or alternatively objects objects (think of values) when you can.

First you need to know if gVector3 fulfils requirements of standard containers, namely if the type gVector3 copyable and assignable. It is useful if gVector3 is default constructible as well (see UPDATE note below). Assuming it does, then you have two choices, store objects of gVector3 directly in std::vector

std::vector<gVector3> points;
points.push_back(gVector(1, 2, 3)); // std::vector will make a copy of passed object

or manage creation (and also destruction) of gVector3 objects manually.

std::vector points; points.push_back(new gVector3(1, 2, 3)); //...

When the points array is no longer needed, remember to talk through all elements and call delete operator on it.

Now, it's your choice if you can manipulate gVector3 as objects (you can assume to think of them as values or value objects) because (if, see condition above) thanks to availability of copy constructor and assignment operator the following operations are possible:

gVector3 v1(1, 2, 3);
gVector3 v2;
v2 = v1; // assignment
gVector3 v3(v2); // copy construction

or you may want or need to allocate objects of gVector3 in dynamic storage using new operator. Meaning, you may want or need to manage lifetime of those objects on your own.

By the way, you may be also wondering When should I use references, and when should I use pointers?

UPDATE: Here is explanation to the note on default constructibility. Thanks to Neil for pointing that it was initially unclear. As Neil correctly noticed, it is not required by C++ standard, however I pointed on this feature because it is an important and useful one. If type T is not default constructible, what is not required by the C++ standard, then user should be aware of potential problems which I try to illustrate below:

#include <vector>
struct T
{
    int i;
    T(int i) : i(i) {}
};
int main()
{
    // Request vector of 10 elements
    std::vector<T> v(10); // Compilation error about missing T::T() function/ctor
}
mloskot
You are right about the copyable and assignable requirements - you are wrong about default constructible - there is no such requirement.
anon
+1 for very good point. I've updated my answer to make it more clear. Thanks!
mloskot
You can say: std::vector<T> v(10, T(0)); I also made this mistake - you can see it my blog entry on the default constructor at http://punchlet.wordpress.com/2009/12/03/letter-the-third.
anon
Yes, that's correct but tightly related to this particular example of type T (or the type from your blog which is similar). However, sometimes a type is more complex and it's not easy or even possible to mimic dummy or default constructibility.
mloskot