avoiding raw pointers

Started by
7 comments, last by iMalc 18 years, 7 months ago
Hi all, I have a class that has a function that returns a pointer to a private instance of another class that's member of this first class :

class other_class
{
    // ...
};


class some_class
{
public:
    //...
    other_class* get_the_other_class(const unsigned int &num) const
    {
        if (the_other_classes.size() < num)
            return &the_other_classes[num];
        else 
            return NULL;
    };
    
private:
    std::vector<other_class> the_other_classes;
    //...
};

since i'm trying to avoid raw pointers... Is there a way to return this class without copying it? Or a different way to have some class use this the_other_class? But : without to copying it or creating lots of get functions in some_class that use get functions of the_other_class that use get_functions of instances of classes in the_other_class, etc... I'm not looking for friend classes, superclasses or smartpointers. other_class should remain a private member of some_class. in practice: I have the model class which consists of model_object classes (in a vector) which consists of geomitry_node classes (in a vector) i need a function to send geomitry_nodes to the renderqueue (sorts them by material and render state changes) to the frustum culler (sets a boolean if they have to be rendered by the renderer) and to the renderer. I don't want to copy them all the time. But I also want them to be in the structure above, since that seems logical. These strict rules of programming OO seem to make things harder for me, since I don't have a lot of experience. Please help, Marty
_____ /____ /|| | || MtY | ||_____|/Marty
Advertisement
I'm not completely sure what the problem is (other than the obvious encapsulation one).

But - if you need to send a pointer (and if you don't want to copy it, it's either that or a reference) to a render queue, then you could use a const * const.

Jim.
maybe using boost::shared_ptr in the vector, instead of actual instances?

edit: thanx, jim... so i should make the pointers const * const? the problem is that the class model_node has boost::shared_array pointers that contain the vertexes, texture coordinates, etc. They are not initialized yet, so making them const won't work, will it?
_____ /____ /|| | || MtY | ||_____|/Marty
hmm.

does the function (in a class where the_int is private) just return a reference instead of copying the int?

int &getint() const{    return the_int;}



than what happenes to the_int if i do this:

    int i = the_instance.getint();    i = 8;


if it would change the value of the_int it would be able to change a private member of the_instance. Otherwise it would copy the_int to i when i use operator = ???

I get the pointers and the address operators, but references are vague to me.

Thanx,
Marty
_____ /____ /|| | || MtY | ||_____|/Marty
References are identical to pointers except that they are always implicitly dereferenced when you access them, so you cannot make them point to something else (they also must be initialised):
int i;int & ir = i; // equivalent to int * ir = &iint * ip = &iir = 7; // equivalent to *ip = 7;int j = 42;ir = j; // equivalent to *ip = j;, not ip = &j++ir; // equivalent to ++*ip;, not ++ip;int * ip2 = &ir // equivalent to int * ip2 = &*ip;, not int * ip2 = &ip

So if you do int & ir = object.getint(); ir = 8; then the int in the object will have its value changed to 8. To avoid this use a const reference (int const & getint(){return the_int;}).

Enigma
If your vector is a vector of actual objects (not pointers to objects), then you're asking for trouble.
If you return a pointer to an element in a vector, that pointer is only guaranteed to be valid until you perform a non-const operation on the vector. For example, if you return a pointer to element 0, and then push_back() another element, your pointer is likely to be invalid, and you'll get an access violation.
Also beware that your class should implement a copy constructor and an operator=() if it has a costructor/destructor.

I always prefer to store pointers to classes in vectors, and then I'd just return a pointer to the object in a function like yours.
Quote:Original post by Marty666
in practice:

I have the model class
which consists of model_object classes (in a vector)
which consists of geomitry_node classes (in a vector)

i need a function to send geomitry_nodes to the renderqueue (sorts them by material and render state changes) to the frustum culler (sets a boolean if they have to be rendered by the renderer) and to the renderer. I don't want to copy them all the time. But I also want them to be in the structure above, since that seems logical.


Why not give the model object a method to add itself to the render queue? That's the way my engine works. Any object which can be rendered inherits from the interface IRenderable, which has a method to add itself to a render queue, and to render itself. Renderable objects override this as they see fit.

That way, the external classes don't need to know anything about the geometry node class.



Quote:Original post by Enigma
References are identical to pointers except that they are always implicitly dereferenced when you access them


It's not really a good idea to think of reference types like that, the standard doesn't state how reference types should be implementated therefore a compiler can represent them in any way, even apply optimization. A compiler in trivial cases could optimize such that a reference type doesn't even exist in generated code it will be the actual instance, in non-trivial cases its most likely to be representated as pointers. The best way to think of reference types is as what they are, a named alias for another instance don't think of them as pointers at all.

Quote:Original post by Evil Steve
If your vector is a vector of actual objects (not pointers to objects), then you're asking for trouble.


Only if your not sure what you are doing.

Quote:Original post by Evil Steve
If you return a pointer to an element in a vector, that pointer is only guaranteed to be valid until you perform a non-const operation on the vector. For example, if you return a pointer to element 0, and then push_back() another element, your pointer is likely to be invalid, and you'll get an access violation.


To avoid this pitfall you could either use std::vector::reserve to allocate a chunk of uninitialized memory in advance or if you have no idea (roughly) how many elements to reserve and elements stored in memory contiguously is insignificant consider using std::deque instead.

Quote:Original post by Evil Steve
Also beware that your class should implement a copy constructor and an operator=() if it has a costructor/destructor.


Copy construction & assignment is implicitly defined for all user-defined types which does a member-wise (or bitwise if it's a POD-class type) copy, always prefer compiler generated ones except where the defaults do shallow copies and you need deep copy semantics.

Quote:Original post by Evil Steve
I always prefer to store pointers to classes in vectors


It's better & more efficient to prefer storing the actual type, only store pointers when you have to that is generally when:


  • Dealing with polymorphic types, you have no choice but to store pointers to get dynamic dispatch/binding & avoid object slicing

  • Dealing with user-defined types that have disabled copy/value semantics, by declaring copy constructor & assignement operator private/protected (ala C++ iostreams)

  • Dealing with user-defined types with expensive & non-trivial copy construction generally the case with large instances, you might need to profile that before you know for sure.

  • Sharing instances with other containers that solely own them already



For example something like a vertex buffer using a vector of 2/3/4-vector you wouldn't store pointers to them in the vector that would be inefficient and generally you would lose elements held in memory contiguously therefore lose out on some possible optimizations.

Like if you had a vector/C-style array of POD-types and you used std::copy, on modern C++ compilers it will dispatch at compile-time to use memmove instead of generic slow copy.

On top of that you can custom memory schemes/models with standard library containers as they are parameterized by allocator type (which defaults to use std::allocator).

[Edited by - snk_kid on September 15, 2005 7:34:43 AM]
Quote:Original post by Marty666
hmm.

does the function (in a class where the_int is private) just return a reference instead of copying the int?

*** Source Snippet Removed ***


than what happenes to the_int if i do this:

*** Source Snippet Removed ***

if it would change the value of the_int it would be able to change a private member of the_instance. Otherwise it would copy the_int to i when i use operator = ???

I get the pointers and the address operators, but references are vague to me.

Thanx,
Marty
Not quite. If you wanted to modify what the returned reference referred to you'd have to do it like this afaik:
    the_instance.getint() = 8;
You were first making a copy of the int from the reference and only modifying the copy.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms

This topic is closed to new replies.

Advertisement