How to store the same instance of one object in multiple vectors?

If I have a class object and multiple vectors, how do I make sure I store the same instance of that object in both vectors? For instance:
1
2
3
4
5
Object object;
std::vector<Object> vectorOne;
std::vector<Object> vectorTwo;
vectorOne.push_back(object);
vectorTwo.push_back(object);


Are the objects in both vectors the same instance of the object? Like if I called vectorOne[0].setValue(somethingDifferent); would the value be changed for the object in both vectorOne and vectorTwo? If not, how do I make sure that I only have one instance of the object I'm trying to store in multiple vectors?
Are the objects in both vectors the same instance of the object?

No. vector::push_back(obj) stores a copy of obj in the vector. If you want to have the same instance in both vectors then you'll need to use a vector of pointers:
1
2
3
4
5
Object object;
std::vector<Object*> vectorOne;
std::vector<Object*> vectorTwo;
vectorOne.push_back(&object);
vectorTwo.push_back(&object);

Any time you create a collection of pointers you need to be crystal clear about who owns the objects that are pointed to? This boils down to "who is responsible for deleting them?" Don't do this as an afterthought - it needs to be defined first and then all code needs to obey the rule.
Alright, got it. So if I used a function to add the object to the vectors, how would that look? Here's what I have that doesn't throw any errors:
1
2
3
4
5
6
7
8
class Class{
	//...
	void AddObject(Object object){ vectorOne.push_back(&object); }
	std::vector<Object*> vectorOne;
};
	//then when calling it
	AddObject(object);
//and do the same thing for the other vectors 


Does this make sure that there is only one instance of the object even in multiple vectors?
closed account (D80DSL3A)
Not as you've implemented it. You are passing object by value to the add object function. A local copy of object is created for use in the function. You are storing a pointer to a local copy (out of scope when function exits), not a pointer to object in main(). This can cause big problems.
Pass object by reference instead.
Here's some sample code to demonstrate the problem with pass by value here.
I defined a copy ctor for the Object class so we can see that a temp instance is created when the
void showCopyOfObject_Address( Object obj ) function is called.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<iostream>

class Object
{
    public:
    int x;
    Object():x(0){}
    Object( const Object& rObj ): x(rObj.x) { std::cout << "Object copy ctor called.\n"; }
};

void showCopyOfObject_Address( Object obj )
{
    std::cout << "In  scooa function: &obj = " << &obj << '\n';
}

void showReferenceToObject_Address( Object& obj )
{
    std::cout << "In  srtoa function: &obj = " << &obj << '\n';
}

int main()
{
    Object object;
   std:: cout << "In main: &object = " << &object << '\n';// address in main
    showReferenceToObject_Address( object );
    showCopyOfObject_Address( object );
    return 0;
}

Output:

In main: &object = 0x23fe30
In  srtoa function: &obj = 0x23fe30
Object copy ctor called.
In  scooa function: &obj = 0x23fe40
Last edited on
As I said in my first post, you need to decide who owns the objects that the vector points to. The problem that funcode2 points out demonstrates why this is so important.
@dhayden a class called Board holds the instances, and whenever the current Board object is destroyed and a new one is loaded can I then delete all the pointers in Board's destructor?

And so basically, the change I need to make in my implentation is passing by reference in the function paramters? Like so void AddObject(Object &object){ vectorOne.push_back(&object); }

Edit: This seems to work, because across all vectors the object's value is changed when I change it for one vector. However, when actually trying to draw these objects, the screen seems to be glitching out. I have the code set up like this:
1
2
3
4
5
6
7
8
//loop through all vectors of objects
if(object.drawn == false){
window.draw(object);
object.drawn = true;
}

//then after the gameloop is done
object.drawn = false;


I have it set up like this because multiple vectors have the oppurtunity to own a pointer to object, so the object is possibly being drawn multiple times as those vectors loop through themselves. This may be an SFML question at this point, but I still feel like I'm doing something wrong on the c++ side of things.
So like once every 100 loops or so, the window actually displays the objects, otherwise it stays empty.
Last edited on
dhayden wrote:
Any time you create a collection of pointers you need to be crystal clear about who owns the objects that are pointed to? This boils down to "who is responsible for deleting them?" Don't do this as an afterthought - it needs to be defined first and then all code needs to obey the rule.

This.

When you have a dynamically allocated object, you must keep track of it and ensure appropriate deletion.

When you have more than one "pointers" to such object and one is the owner, how do you ensure that non-owners are removed before the deletion? The std::shared_ptr is one answer: they are all owners and the last to go does the delete.
So would my class that holds the objects still have a vector of regular objects? I.e. std::vector<Object> vectorOne; And then in other classes that have vectors of pointers to those objects I would do this? std::vector<std::shared_ptr<Object>> vectorPointerOne; Or would all vectors, even the one which holds the actual instances, be vectors of shared pointers?
No. As has been said already, when you pass an object into a vector, that creates copies of those objects that are managed by the vector. Any pointers you have to the objects in the vector would be unreliable, because the vector can manage its own memory, allocating and deleting new memory as it chooses.

If you want pointers to objects, you'll have to have some part of your program take ownership of those objects.
Last edited on
If you want pointers to objects, you'll have to have some part of your program take ownership of those objects.
Got it.
I'm having trouble implementing the std::shared_ptr into my functions. Taking my example from earlier, I've changed my function definitions to
1
2
3
4
5
class Class{
	//...
	void AddObject(Object &object){ vectorOne.push_back(&object); }
	std::vector<std::shared_ptr<Object*>> vectorOne;
};


However, I get the error
error C2664: 'void std::vector<_Ty>::push_back(std::shared_ptr<Object *> &&)' : cannot convert parameter 1 from 'Object' to 'std::shared_ptr<_Ty> &&'


I've checked the links as well as SO but I'm still confused on how to actually store these shared_ptr's into vectors and work with them.
Last edited on
> I'm still confused on how to actually store these shared_ptr's into vectors and work with them.

Here is some sample starter code for you; it should give you the overall idea of how you could do this.
(caveat: completely untested).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <iostream>
#include <vector>
#include <set>
#include <functional>
#include <memory>

// http://en.cppreference.com/w/cpp/memory/enable_shared_from_this
struct object : std::enable_shared_from_this<object>
{
    using pointer = std::shared_ptr<object> ;
    static pointer create( /* ... */ ) { return pointer( new object( /* ... */  ) ) ; }

    // http://en.cppreference.com/w/cpp/memory/enable_shared_from_this/shared_from_this
    // use std::addressof if the actual afress is required
    pointer operator& () { return shared_from_this() ; }

    ~object() { objects.erase(this) ; }

    void paint()
    {
        if( !painted )
        {
            std::cout << "paint { object #" << id << " at " << this << " }\n" ;
            painted = true ;
        }
    }

    void refresh() { painted = false ; }
    static void refresh_all() { for_each( &object::refresh ) ; }

    static void for_each( std::function< void(object*) > fn )
    { for( auto p : objects ) fn(p) ; }

    private:
        object( /* ... */ ) : id(cnt++) { objects.insert(this) ; }

        object( const object& ) = delete ;
        // object& operator= ( const object& ) = delete ; // implicitly deleted

        const int id ;
        bool painted = false ;

        static std::set<object*> objects ;
        static int cnt ;

};

std::set< object* > object::objects ;
int object::cnt = 0 ;

int main()
{
    std::vector< object::pointer > seq_one ;
    for( int i = 0 ; i < 8 ; ++i ) seq_one.push_back( object::create() ) ;

    std::vector< object::pointer > seq_two { seq_one[0], seq_one[3], seq_one[6], seq_one[3], seq_one[6] };
    std::vector< object::pointer > seq_three { seq_one[5], seq_one[2], seq_one[3], seq_one[6], seq_one[0] };

    for( object::pointer p : seq_two ) p->paint() ;
    for( object::pointer p : seq_three ) p->paint() ;
    for( object::pointer p : seq_one ) p->paint() ;
    std::cout << "---------------------------\n" ;
    
    object::refresh_all() ; // now we can paint all the objects again
    
    seq_one.push_back( object::create() ) ;
    seq_two.push_back( object::create() ) ;
    seq_three.push_back( seq_two.front() ) ;

    // ...
    for( object::pointer p : seq_two ) p->paint() ;
    for( object::pointer p : seq_three ) p->paint() ;
    for( object::pointer p : seq_one ) p->paint() ;
    std::cout << "---------------------------\n" ;
}

http://coliru.stacked-crooked.com/a/d4a68853183db39a
I'm having trouble implementing the std::shared_ptr into my functions.

You've declared your shared pointers to point to Object*, not Object. It should be:

std::vector<std::shared_ptr<Object>> vectorOne;
Last edited on
@MikeyBoy, okay, but even when I do that then the objects don't seem to be returned correctly. The code looks like this:
1
2
3
4
5
6
7
8
9
std::vector<std::shared_ptr<MoveableObject>> movableObjects_;

//...
void GridSquare::AddMovableObject(MoveableObject &object){
	movableObjects_.push_back(std::make_shared<MoveableObject>(object));
}
std::vector<std::shared_ptr<MoveableObject>> &GridSquare::GetMovableObjects(){
	return movableObjects_;
}
I'm not sure if I did this correctly or if I just need a new way of handling these objects, but when I try to draw objects from the movableObjects_; vector using window.draw(board.GetGrid()[i].GetGridObjects()[j]->GetActiveSprite()); //this line of code worked when I was just using regular pointers, and quit drawing anything when I switched to shared_ptr's nothing is drawn on the screen. This same code worked when my class just held vectors of regular pointers, but when I implemented shared pointers the screen quit drawing anything.
The code you've posted for your movableObjects_, AddMovableObject() and GetMovableObjects() looks OK to me. I'd recommend defining a typedef for std::vector<std::shared_ptr<MoveableObject>> to make your code a bit easier to read, but that's a matter of style.

Without knowing anything about that draw method, we have no way of knowing why it might not be drawing.

At this point, the most productive thing you can do is run the code through a debugger so that you can examine the state of the memory at various points at which you're using that array.
The SFML draw method, explained here http://www.sfml-dev.org/documentation/2.2/classsf_1_1Drawable.php and looks like
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class MyDrawable : public sf::Drawable
{
public:

   ...

private:

    virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
    {
        // You can draw other high-level objects
        target.draw(m_sprite, states);

        // ... or use the low-level API
        states.texture = &m_texture;
        target.draw(m_vertices, states);

        // ... or draw with OpenGL directly
        glBegin(GL_QUADS);
        ...
        glEnd();
    }

    sf::Sprite m_sprite;
    sf::Texture m_texture;
    sf::VertexArray m_vertices;
};

So each object calls this draw method implicitly, as it is a pure virtual function. So in the code, m_sprite is the same thing as the object that my smart pointer is pointing to, because each object owns a sf::sprite object.
Last edited on
Topic archived. No new replies allowed.