I have a class setup analogous to this:
class BlimpBase{
public:
virtual ~BlimpBase();
private:
virtual void lift()const = 0;
};
class Blimp: protected BlimpBase{
void lift()const;
};
class BlimpCarrier{
public:
add_blimp(BlimpBase& blimp);
private:
std::vector<BlimpBase* blimp> blimps;
};
As you can see, I have a set of polymorphic blimp classes and I am trying to store then as "references" in the vector by using pointers (I realize you can't store references in vectors, I just don't know how else to describe them). The problem is that most of these objects are allocated on the stack as class members, but I want to add them to this vector so that I can directly modify them (copies won't do). The problem with keeping pointers to these objects is that if these objects go out of scope before the BlimpCarrier does (since they are on the stack), I will have a dangling pointer. I looked into std::unique_ptr and std::shared_ptr, but I don't think I can use them here...
Assuming you CAN change where they are allocated on the stack, or the classes that have them as members, then you can try this with std::weak_ptr:
class BlimpCarrier{
public:
add_blimp(std::shared_ptr<BlimpBase>& blimp_ptr)
{
blimps.push_back(blimp_ptr);
}
private:
std::vector<std::weak_ptr<BlimpBase>> blimps;
};
BlimpCarrier globalCarrier;
void foo()
{
std::shared_ptr<BlimpBase> instance(new BlimpSubClass());
globalCarrier.add_blimp(instance);
}
You need an extra step, that when you traverse the vector that you check that the weak_ptr objects have been "Expired" or not, and then remove them yourself from the vector. I'd actually suggest using a std::list instead for a linked list implementation for this type of thing. See cppreference.com for a good example for how to correctly and safely use weak_ptr.
Related
I have a tricky situation. Its simplified form is something like this
class Instruction
{
public:
virtual void execute() { }
};
class Add: public Instruction
{
private:
int a;
int b;
int c;
public:
Add(int x, int y, int z) {a=x;b=y;c=z;}
void execute() { a = b + c; }
};
And then in one class I do something like...
void some_method()
{
vector<Instruction> v;
Instruction* i = new Add(1,2,3)
v.push_back(*i);
}
And in yet another class...
void some_other_method()
{
Instruction ins = v.back();
ins.execute();
}
And they share this Instruction vector somehow. My concern is the part where I do "execute" function. Will it work? Will it retain its Add type?
No, it won't.
vector<Instruction> ins;
stores values, not references. This means that no matter how you but that Instruction object in there, it'll be copied at some point in the future.
Furthermore, since you're allocating with new, the above code leaks that object. If you want to do this properly, you'll have to do
vector<Instruction*> ins
Or, better yet:
vector< std::reference_wrapper<Instruction> > ins
I like this this blog post to explain reference_wrapper
This behavior is called object slicing.
So you will need some kind of pointer. A std::shared_ptr works well:
typedef shared_ptr<Instruction> PInstruction;
vector<PInstruction> v;
v.emplace_back(make_shared<Add>());
PInstruction i = v[0];
Keep in mind that PInstruction is reference-counted, so that the copy constructor of PInstruction will create a new "reference" to the same object.
If you want to make a copy of the referenced object you will have to implement a clone method:
struct Instruction
{
virtual PInstruction clone() = 0;
...
}
struct Add
{
PInstruction clone() { return make_shared<Add>(*this); }
...
}
PInstruction x = ...;
PInstruction y = x->clone();
If performance is an issue than you can look at std::unique_ptr, this is a little trickier to manage as move semantics are always required, but it avoids the cost of some atomic operations.
You can also use raw pointers and manage the memory manually with some sort of memory pool architecture.
The underlying problem is that to have a polymorphic type the compiler doesn't know how big the subclasses are going to be, so you can't just have a vector of the base type, as it won't have the extra space needed by subclasses. For this reason you will need to use pass-by-reference semantics as described above. This stores a pointer to the object in the vector and then stores the object on the heap in blocks of different sizes depending on what the subclass needs.
No, that will not work; you are "slicing" the Add object, and only inserting its Instruction part into the array. I would recommend that you make the base class abstract (e.g. by making execute pure virtual), so that slicing gives a compile error rather than unexpected behaviour.
To get polymorphic behaviour, the vector needs to contain pointers to the base class.
You will then need to be careful how you manage the objects themselves, since they are no longer contained in the vector. Smart pointers may be useful for this; and since you're likely to be dynamically allocating these objects, you should also give the base class a virtual destructor to make sure you can delete them correctly.
You may want to do a couple things, A: change the type of "v" to "vector", B: managed your memory with the "delete" operator. To answer your question, with this approach, yes, but you will only be able to access the interface from "Instruction", if you KNOW the type of something an "Instruction" pointer is pointing to I would suggest using dynamic_cast if you need to access the interface from, say, "Add".
There are some objects that are Drawable and some that are Movable.
All movable objects are dawable.
I store all the drawable objects in a vector called drawables and movable objects in a vector called movables.
I also have vectors ships and bullets which contain objects of type Ship and Bullet respectively.
Ship and Bullet both are Movable
Here's the structure of the classes:
class Drawable {
public:
void draw();
};
class Movable : public Drawable {
public:
void move();
}
class Ship : public Movable {
public:
Ship();
}
class Bullet : public Movable {
public:
Bullet();
}
The vectors are declared as follows:
std::vector<Drawable*> drawables;
std::vector<Movable*> movables;
std::vector<Ship*> ships;
std::vector<Bullet*> bullets;
The thing is, that each time I create a Ship I have to add it in all the vectors i.e.
drawables.push_back(ship);
movables.push_back(ship);
ships.push_back(ship);
I have created separate drawables and movables vectors since I have a draw() function which calls the draw() method of all objects in the drawables vector. Similarly, I have a move() function which calls the move() method of all objects in the movables vector.
My question is, how do I change the structure to prevent adding the same thing in different vectors. I also need to remove objects from all the vectors once it's purpose is done.
For example, once the bullet hits someone or moves out of the screen, then I'll have to remove it from the vectors drawables, movables and bullets after searching it in all three vectors.
It seems like I'm not using the correct approach for storing these objects. Please suggest an alternative.
This seems more like a software engineering question than a coding question. Please migrate the question to other forum if necessary.
Assuming you are using a reasonably modern compiler, this is exactly why shared_ptr exists.
The problem is that you have no idea which vector owns the object, so you don't know which one to delete. shared_ptr takes are of this for you: it manages the lifetime of the object, and will delete it once the last reference to the object is destroyed.
To create a new Ship, you could do something like this:
auto ship = std::make_shared<Ship>();
drawables.push_back(ship);
movables.push_back(ship);
ships.push_back(ship);
At this point ship has 4 references (one for each vector, and the ship variable itself). It will automatically be deleted once it has been removed from all three vectors and the local variable goes out of scope.
If you are going to maintain a container of (pointers to) all objects of a certain type, you may want to take a RAII approach. Have the object's constructor add to the container, and the destructor remove from it. You'd also want to make sure nothing else modifies the container, so it should be a private (static) member of your class, with a public method to provide read-only access.
Even better, move this logic into its own class, so it can be re-used. This would also allow your existing containers to remain focused on what they currently do. They would just need a new data member of the helper class type.
To ease removals, I would consider using a list instead of a vector. Also, it might be worth using reference_wrapper instead of pointers. A pointer can have a null value. While you can document that the container will have no null pointers, a reference_wrapper conveys this with no additional documentation.
To get you started, here is the start of a helper class template you could use.
template <class T>
class All {
using ListType = std::list< std::reference_wrapper<T> >;
private:
static ListType the_list;
// A list's iterators are rarely invalidated. For a vector, you would
// not store an iterator but instead search when removing from the_list.
typename ListType::iterator list_it;
public:
// Read-only access to the list.
static const ListType & list() { return the_list; }
// Construction
ListAll() : list_it(the_list.end()) {} // If this constructor is needed
explicit ListAll(T & data) : list_it(the_list.insert(the_list.end(), data)) {}
// Destruction
~ListAll() { if ( list_it != the_list.end() ) the_list.erase(list_it); }
// Rule of 5
// You should also define or delete the copy constructor, move constructor,
// copy assignment, and move assignment.
// If you need the default constructor, then you probably want a method like:
//void set(T & data);
};
template <class T>
typename All<T>::ListType All<T>::the_list{};
Names are often tough to come by. I named this template based on getting something to iterate over, for example: All<Movable>::list().
I have a tricky situation. Its simplified form is something like this
class Instruction
{
public:
virtual void execute() { }
};
class Add: public Instruction
{
private:
int a;
int b;
int c;
public:
Add(int x, int y, int z) {a=x;b=y;c=z;}
void execute() { a = b + c; }
};
And then in one class I do something like...
void some_method()
{
vector<Instruction> v;
Instruction* i = new Add(1,2,3)
v.push_back(*i);
}
And in yet another class...
void some_other_method()
{
Instruction ins = v.back();
ins.execute();
}
And they share this Instruction vector somehow. My concern is the part where I do "execute" function. Will it work? Will it retain its Add type?
No, it won't.
vector<Instruction> ins;
stores values, not references. This means that no matter how you but that Instruction object in there, it'll be copied at some point in the future.
Furthermore, since you're allocating with new, the above code leaks that object. If you want to do this properly, you'll have to do
vector<Instruction*> ins
Or, better yet:
vector< std::reference_wrapper<Instruction> > ins
I like this this blog post to explain reference_wrapper
This behavior is called object slicing.
So you will need some kind of pointer. A std::shared_ptr works well:
typedef shared_ptr<Instruction> PInstruction;
vector<PInstruction> v;
v.emplace_back(make_shared<Add>());
PInstruction i = v[0];
Keep in mind that PInstruction is reference-counted, so that the copy constructor of PInstruction will create a new "reference" to the same object.
If you want to make a copy of the referenced object you will have to implement a clone method:
struct Instruction
{
virtual PInstruction clone() = 0;
...
}
struct Add
{
PInstruction clone() { return make_shared<Add>(*this); }
...
}
PInstruction x = ...;
PInstruction y = x->clone();
If performance is an issue than you can look at std::unique_ptr, this is a little trickier to manage as move semantics are always required, but it avoids the cost of some atomic operations.
You can also use raw pointers and manage the memory manually with some sort of memory pool architecture.
The underlying problem is that to have a polymorphic type the compiler doesn't know how big the subclasses are going to be, so you can't just have a vector of the base type, as it won't have the extra space needed by subclasses. For this reason you will need to use pass-by-reference semantics as described above. This stores a pointer to the object in the vector and then stores the object on the heap in blocks of different sizes depending on what the subclass needs.
No, that will not work; you are "slicing" the Add object, and only inserting its Instruction part into the array. I would recommend that you make the base class abstract (e.g. by making execute pure virtual), so that slicing gives a compile error rather than unexpected behaviour.
To get polymorphic behaviour, the vector needs to contain pointers to the base class.
You will then need to be careful how you manage the objects themselves, since they are no longer contained in the vector. Smart pointers may be useful for this; and since you're likely to be dynamically allocating these objects, you should also give the base class a virtual destructor to make sure you can delete them correctly.
You may want to do a couple things, A: change the type of "v" to "vector", B: managed your memory with the "delete" operator. To answer your question, with this approach, yes, but you will only be able to access the interface from "Instruction", if you KNOW the type of something an "Instruction" pointer is pointing to I would suggest using dynamic_cast if you need to access the interface from, say, "Add".
If I have several levels of object containment (one object defines and instantiates another object which define and instantiate another object..), is it possible to get access to upper, containing - object variables and functions, please?
Example:
class CObjectOne
{
public:
CObjectOne::CObjectOne() { Create(); };
void Create();
std::vector<ObjectTwo>vObejctsTwo;
int nVariableOne;
}
bool CObjectOne::Create()
{
CObjectTwo ObjectTwo(this);
vObjectsTwo.push_back(ObjectTwo);
}
class CObjectTwo
{
public:
CObjectTwo::CObjectTwo(CObjectOne* pObject)
{
pObjectOne = pObject;
Create();
};
void Create();
CObjectOne* GetObjectOne(){return pObjectOne;};
std::vector<CObjectTrhee>vObjectsTrhee;
CObjectOne* pObjectOne;
int nVariableTwo;
}
bool CObjectTwo::Create()
{
CObjectThree ObjectThree(this);
vObjectsThree.push_back(ObjectThree);
}
class CObjectThree
{
public:
CObjectThree::CObjectThree(CObjectTwo* pObject)
{
pObjectTwo = pObject;
Create();
};
void Create();
CObjectTwo* GetObjectTwo(){return pObjectTwo;};
std::vector<CObjectsFour>vObjectsFour;
CObjectTwo* pObjectTwo;
int nVariableThree;
}
bool CObjectThree::Create()
{
CObjectFour ObjectFour(this);
vObjectsFour.push_back(ObjectFour);
}
main()
{
CObjectOne myObject1;
}
Say, that from within CObjectThree I need to access nVariableOne in CObjectOne. I would like to do it as follows:
int nValue = vObjectThree[index].GetObjectTwo()->GetObjectOne()->nVariable1;
However, after compiling and running my application, I get Memory Access Violation error.
What is wrong with the code above(it is example, and might contain spelling mistakes)?
Do I have to create the objects dynamically instead of statically?
Is there any other way how to achieve variables stored in containing objects from withing contained objects?
When you pass a pointer that points back to the container object, this pointer is sometimes called a back pointer. I see this technique being used all the time in GUI libraries where a widget might want access to its parent widget.
That being said, you should ask yourself if there's a better design that doesn't involve circular dependencies (circular in the sense that the container depends on the containee and the containee depends on the container).
You don't strictly have to create the objects dynamically for the back pointer technique to work. You can always take the address of a stack-allocated (or statically-allocated) object. As long as the life of that object persists while others are using pointers to it. But in practice, this technique is usually used with dynamically-created objects.
Note that you might also be able to use a back-reference instead of a back-pointer.
I think I know what's causing your segmentation faults. When your vectors reallocate their memory (as the result of growing to a larger size), the addresses of the old vector elements become invalid. But the children (and grand-children) of these objects still hold the old addresses in their back-pointers!
For the back-pointer thing to work, you'll have to allocate each object dynamically and store their pointers in the vectors. This will make memory management a lot more messy, so you might want to use smart pointers or boost::ptr_containers.
After seeing the comment you made in another answer, I now have a better idea of what you're trying to accomplish. You should research generic tree structures and the composite pattern. The composite pattern is usually what's used in the widget example I cited previously.
Maybe all your object can inherit from a common interface like :
class MyObject
{
public:
virtual int getData() = 0;
}
And after you can use a std::tree from the stl library to build your structure.
As Emile said, segmentation fault is caused by reallocation. Exactly speaking -- when the local stack objects' 'this' pointer was passed to create another object, which is then copied to the vector container. Then the 'Create()' function exits, the stack frame object ceases to exist and the pointer in the container gets invalid.
I have a class that creates an object inside one public method. The object is private and not visible to the users of the class. This method then calls other private methods inside the same class and pass the created object as a parameter:
class Foo {
...
};
class A {
private:
typedef scoped_ptr<Foo> FooPtr;
void privateMethod1(FooPtr fooObj);
public:
void showSomethingOnTheScreen() {
FooPtr fooObj(new Foo);
privateMethod1(fooObj);
};
};
I believe the correct smart pointer in this case would be a scoped_ptr, however, I can't do this because scoped_ptr makes the class non copyable if used that way, so should I make the methods like this:
void privateMethod1(FooPtr& fooObj);
privateMethod1 doesn't store the object, neither keeps references of it. Just retrieves data from the class Foo.
The correct way would probably be not using a smart pointer at all and allocating the object in the stack, but that's not possible because it uses a library that doesn't allow objects on the stack, they must be on the Heap.
After all, I'm still confused about the real usage of scoped_ptr.
One further possibility is to create the object as a static_ptr for ease of memory management, but just pass the raw pointer to the other private methods:
void privateMethod1(Foo *fooObj);
void showSomethingOnTheScreen() {
scoped_ptr<Foo> fooObj(new Foo);
privateMethod1(fooObj.get());
};
I would use scoped_ptr inside showSomethingOnTheScreen, but pass a raw pointer (or reference) to privateMethod1, e.g.
scoped_ptr<Foo> fooObj(new Foo);
privateMethod1(fooObj.get());
Use here simple std::auto_ptr as you can't create objects on the stack. And it is better to your private function just simply accept raw pointer.
Real usage is that you don't have to catch all possible exceptions and do manual delete.
In fact if your object is doesn't modify object and your API return object for sure you'd better to use
void privateMethod1(const Foo& fooObj);
and pass the object there as
privateMethod1(*fooObj.get());
I'm suspicious about the comment "it uses a library that doesn't allow objects on the stack, they must be on the Heap."
Why? That typically means that they must be deallocated in some special way - so perhaps none of these solutions will work.
In that case, you only have to replace the allocation mechanism.
Create the object on the heap, but pass the object as reference to private methods.
class A {
private:
void privateMethod1(Foo& fooObj);
public:
void showSomethingOnTheScreen() {
scoped_ptr<Foo> fooObj(new Foo);
privateMethod1(*(fooObj.get()));
};
};