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'm trying to make the Thompson's construction algorithm in c++ (I'm somewhat new to the language). But I'm having some difficulties on implementing a destructor for my class NFiniteAutomaton. In some part of the constructor of NFiniteAutomaton I have:
NFiniteAutomaton() = default;
NFiniteAutomaton(std::string regex){
// A lot of code here
// ....
NFiniteAutomaton single_ele;
single_ele.init_state = new State;
single_ele.final_state = new State;
// A lot of code here
// ....
}
Then in other parts of my code, I create pointers to single_ele.init_state's and single_ele.final_state's content in the main NFiniteAutomaton, because I want to reuse states instead of creating new ones with the same attributes.
The struct State looks like this:
struct State;
struct Transition {
State* to;
std::string symbol;
};
struct State{
std::vector<Transition> transitions;
};
So when I implement a destructor of NFiniteAutomaton that deletes all structs allocated on the heap, my problem is generated, because when single_ele gets out of the scope, it deletes all State pointers including the ones that other automata are using (because destructor gets called). One solution that I thought is to make a method Clear() that deletes all pointers whenever I want, and leave the default destructor. There is a way to implement the destructor of this class only using raw pointers?
One solution that I thought is to make a method Clear() that deletes all pointers whenever I want, and leave the default destructor.
Possible but why create a new function that the user of the class should be aware of instead of making the destructor take care of de-allocating dynamic memory? I wouldn't do that.
You should set your pointers to nullptr, before the destructor of NFiniteAutomaton is called. In the destructor use delete for init and final state.
If you want to make single_ele object persistent outside the constructor, define it as a class property rather than as a local object. The destructor can do its normal cleanup (no need for Clear() function), and the object will call the destructor only at the end of your program.
class NFIniteAutomaton {
protected:
static NFIniteAutomaton single_ele;
...
};
#include <vector>
enum ListOfGameStates
{
// List of game states
};
class GameState()
{
public:
GameStates(); // Initializes protected (global) variables
virtual ListOfGameStates run() = 0;
protected:
// Heavyweigh resource managers containing all resources and other global vars
}
class GameStateManager()
{
public:
GameStateManager(); // Creates all game states
~GameStateManager(); // Deletes all game states
void run(); // Switches from one state to another state
private:
// A vector of raw pointers to game states. GameState is a base class.
std::vector<GameState*> game_states_container;
}
I want to get rid off raw pointers so that I could have no worries about exceptions and clean-up. Is there an easy simple solution (I am a really dumb teen) or is it not worth it? Thanks!
Simply change your vector to:
std::vector<std::unique_ptr<GameState>> game_states_container;
And get rid of any delete in your destructor. In fact you can probably get rid of the destructor entirely unless it has other jobs to do.
unique_ptr is not copyable but it is movable so it is worth having some understanding of C++11 move-semantics. When you want to add a unique_ptr to your container you can use push_back providing you pass a temporary, e.g the return value of a function:
game_states_container.push_back(createGameState());
game_states_container.push_back(std::make_unique<GameStateA>()); // C++14
Or if you have a local unique_ptr variable you can use std::move to move it into the vector:
std::unique_ptr<GameState> game_state = std::make_unique<GameStateA>(); // C++14
// auto game_state = std::unique_ptr<GameState>(new GameStateA); // C++11
...
game_states_container.push_back(std::move(game_state));
It is good practice to put the raw pointers in unique_ptr as soon as you new them (or preferably use std::make_unique). Otherwise, if an exception is thrown between allocation and wrapping in unique_ptr you have a memory leak.
It is unrelated to unique_ptr but your GameState class should have a virtual destructor.
Live demo
I'm looking to do simulations with very complicated initial conditions from the user. I'm writing class A whose member variables need to be initialized by the user before running A.Solve() to get the results stored in a file. The initialization is rather complicated and requires several temporary data structures that will no longer be needed after the initialization. So, I wrote another class called class Initializer which stores a reference to an object of class A. My code will look like this:
class A {
friend class Initializer;
private:
// member variables storing the state of the system
public:
void Solve();
...
};
class Initializer {
private:
A& a
// Other data structures used in the initialization
...
public:
// functions called by the user to set up for the initialization
...
Initialize(); // after this is called, a will be ready to solve
};
int main(...) {
A a;
Initializer init(a);
// call functions on init to initialize the system
...
init.Initialize();
a.Solve();
return 0;
}
But it seems like data structures in init will live on the stack for the entire program. To prevent that, is it ok to do this:
A a;
Initializer *init = new Initializer(a);
....
init.Initialize();
delete init;
a.Solve();
Or does this look unnecessary and should I just have everything contained in class A?
To answer your original line of thought, the usual solution is to restrict the scope of the init variable:
A a;
{
Initializer init(a);
//...
} // init is destroyed as soon as the scope exits
a.Solve();
Your new/delete variant is quite brittle and will leak memory if anything throws between new and delete. To fix that, use smart pointers:
A a;
std::unique_ptr<Initializer> init(new Initializer(a));
//...
init.reset();
a.Solve();
However as others have said, this whole design is kinda weird and probably overkill. If the initialization is really so complicated that you can't get away with constructors then you may want to do it the other way around: instead of Initializer taking an argument A and operating on it, you should pass a fully ready-to-use Initializer to A's constructor, which will in turn either copy the whole Initializer to keep a copy of the data, or just copy the relevant bits. Initializer should then probably be renamed to Config or something like that. Notice how a Config/Initializer object can now be reused to initialize several A objects, and even be modified between two A initializations.
Unfortunately this is hard to give you definitive advice with so little information.
Note: if you use C++11 you may be interested in std::initializer_list which enables the new brace-initialization syntax. Depending on the complexity of your data it may involve more work than your current solution but you'll end up with a very nice and intuitive syntax.
Here, using another class for initialization purpose seem to be overkill.
Just initialize in class A constructor.
Once the constructor execution completes, the temporary data structures will be freed automatically.
is it possible to re-initialize an object of a class using its constructor?
Sort of. Given a class A:
A a;
...
a = A();
the last statement is not initialisation, it is assignment, but it probably does what you want.
Literally? Yes, by using placement new. But first you have to destruct the previously constructed object.
SomeClass object(1, 2, 3);
...
object.~SomeClass(); // destruct
new(&object) SomeClass(4, 5, 6); // reconstruct
...
// Final destruction will be done implicitly
The value of this does not go beyond purely theoretical though. Don't do it in practice. The whole thing is ugly beyond description.
It's possible, although it's a very bad idea. The reason why is that without calling the destructors on the existing object, you are going to leak resources.
With that major caveat, if you insist on doing it, you can use placement new.
// Construct the class
CLASS cl(args);
// And reconstruct it...
new (&cl) CLASS(args);
In C++11, you can do this:
#include <type_traits>
template <class T, typename... Args>
void Reconstruct(T& x, Args&&... args)
{
static_assert(!std::has_virtual_destructor<T>::value, "Unsafe");
x.~T();
new (&x) T(std::forward<Args>(args)...);
}
This allows you to use Reconstruct passing arbitrary constructor parameters to any object. This can avoid having to maintain a bunch of Clear methods, and bugs that can easily go unnoticed if at some point the object changes, and the Clear method no longer matches the constructor.
The above will work fine in most contexts, but fail horribly if the reference is to a base within a derived object that has a virtual destructor. For this reason, the above implementation prevents use with objects that have a virtual destructor.
Short answer:
No. If part of your object's intended behavior is to be initialized several times, then the best way to implement this is through an accessible initialization method. The constructor of your class can simply defer to this method.
class C1 {
public:
C1(int p1, int p2) {
Init(p1,p2);
}
void Init(int p1, int p2) { ... }
};
Nitpicker corner:
Is there some incredibly evil way to call a constructor in C++ after an object is created? Almost certainly, this is C++ after all. But it's fundamentally evil and it's behavior is almost certainly not defined by the standard and should be avoided.
No, constructors are only called when the object is first created. Write a new method to do it instead.
Edit
I will not acknowledge placement new, because I don't want to have to get a pet raptor for work.
See this comic, but think of the topic on hand...
Yes you can cheat and use placement new.
Note: I do not advice this:
#include <new>
reInitAnA(A& value)
{
value.~A(); // destroy the old one first.
new (&value) A(); // Call the constructor
// uses placement new to construct the new object
// in the old values location.
}
I usually write the following in modern C++ :
SomeClass a;
...
a = decltype(a)();
It may be not the most effective way, as it effectively constructs another object of the same type of a and assigns it to a, but it works in most cases, you don't have to remember the type of a, and it adapts if the type changes.
Instead of destructing and reinitializing as suggested by some of the answers above, it's better to do an assignment like below. The code below is exception safe.
T& reinitialize(int x, int y)
{
T other(x, y);
Swap(other); // this can't throw.
return *this;
}
May-be not what you have in mind, but since you didn't mention what it is for, I suppose one answer would be that you'd do it by controlling scope and program flow.
For example, you wouldn't write a game like this:
initialize player
code for level 1
...
reinitialize player
code for level 2
...
etc
Instead you'd strive for:
void play_level(level_number, level_data) {
Player player; //gets "re-initialized" at the beginning of each level using constructor
//code for level
}
void game() {
level_number = 1;
while (some_condition) {
play_level(level_number, level_data);
++level_number;
}
}
(Very rough outline to convey the idea, not meant to be remotely compilable.)
If you really must do this I strongly encourage creating a reset method for this:
class A
{
...
public:
reset() { *this= A() };
}
The above requires A to be copy and move assignable.
That is because the initial unoptimized version will copy from a temp. However copy elision may remove this step.
The behavior of A::reset() is always well defined. It replace the existing data in a valid A instance with a data from a new one. Of course any sub-class of A will still need to define its own version if you wanted its data re-initialized as well. However, failure to do so does not in and of itself invoke undefined or unspecified behavior. It simply means that only whatever memory A uses for its members will be reset. Even the involvement of virtual functions and/or virtual inheritance doesn't change this. Although the usual caveats of using such things apply.
Raw pointers will not be deleted by the above so they will need to be put into a std::shared_ptr or similar construct so the will self destruct when no longer needed.
While most answers are reinitializing an object in two steps; first, creating an initial object, and second creating another object and swapping it with the first one using placement new, this answer covers the case that you first create a pointer to an empty object and later allocate and construct it:
class c *c_instance; // Pointer to class c
c_instance = new c(arg1, ..., argn) // Allocate memory & call the proper constructor
// Use the instance e.g. c->data
delete c_instance; // Deallocate memory & call the destructor
Yes , it is possible.
If you create a method that returns a new object.
#include "iostream"
class a // initialize class
a getNewA(a object){// Create function to return new a object
a new_object(/*Enter parameters for constructor method*/);
return new_object;
}