I have a class, GameObject, which has a std::vector<Component*> mComponents and I have overloaded the GameObject(const GameObject&). I am trying to copy the mComponents over from one to the other, but making each of the contained Component*'s into a new object entirely, but keeping the objects contents exactly the same. This is what I have at the moment:
GameObject.cpp
GameObject::GameObject(const GameObject& other)
{
if (this != &other)
{
this->mComponents = other.mComponents; // EDIT 1
for (int i = 0; i < (int)mComponents.size(); i++)
{
// FILL this->mComponents with NEW objects but
// containing the exact same data and
// variables from other.mComponents
this->mComponents[i] = other.Copy(); // EDIT 2 EXAMPLE OF IDEA IN COMMENTS
this->mComponents[i]->setParent(this);
}
}
}
Engine.cpp (Extract)
GameObject cube, cube2;
cube.addComponent(new DirectionalLight(glm::vec3(-0.2f, -1.0f, -0.3f)));
cube.addComponent(new Texture("Resources/Textures/container.png", "Resources/Textures/container_specular.png"));
cube.addComponent(new Shader("Resources/Shaders/cube.shader"));
cube.addComponent(new Cube());
cube2 = GameObject(cube);
When I instantiate cube2, the mComponents Components* contents all stay exactly the same but I would like to create a new Component*'s to fill this std::vector from the GameObject(const GameObject&) fucntion, whilst keeping all the variables the same.
P.s. I know that most other operators such as '=' will not create new Components for inside the vector but I will be implementing that aswell after I figure out how to fill the vector with new Component*'s.
this->mComponents[i]->Copy(other); Will not work. At least, not from a pure inheritance standpoint. A supertype (base) type pointer cannot be implicitly cast to a derived type. This is called downcasting, and no language supports it implicitly.
A simpler way to do it is to define a virtual "clone" function in each component:
virtual Component* clone()=0; // base declaration
virtual Component* Texture::clone() //derived implementation
{
return new Texture(*this);
}
Then in your game object copy constructor:
for (int i = 0; i < (int)other.mComponents.size(); i++)
{
// FILL this->mComponents with NEW objects but
// containing the exact same data and
// variables from other.mComponents
this->mComponents.push_back(other.mComponents->clone());
this->mComponents[i]->setParent(this);
}
This way, you let the component itself handle the copying process.
Related
I am trying to write a class function that can be called to dynamically create a new derived object and add that object to a dynamically allocated array that stores pointers to objects of the base class. If I run the function twice, I can access objectAry[0], but accessing objectAry[1] gives me read access violations. Can anyone tell me why this isn't storing the objects appropriately?
The objectAry was dynamically allocated with space for 10 objects, so there is room in position 1. This occurs even when newObject() is only called twice.
//Array definition (outside of function):
Base* objectAry;
objectAry = new Derived[10]
//Function in question:
void Derived::newObject()
{
Derived* tempObject = NULL;
tempObject = new Derived;
objectAry[numObjects] = *tempObject;
numObjects++;
delete tempObject;
tempObject = NULL;
}
When running a simple function to return one of the derived object's member variables:
Exception thrown: read access violation.
this->objectAry+1-> was 0x1.
Clearly I'm storing this incorrectly, but I'm not sure how to get this working.
First, in reference to:
//Array definition (outside of function):
Base* objectAry;
objectAry = new Derived[10];
A pointer to Base is allocated, but assigned a const pointer to the array of class Derived. This does not cause the fault, but sets up the subsequent code to fail.
In reference to the following statement,
objectAry[numObjects] = *tempObject;
the compiler views objectAry as an array of class Base. The sizeof(Base) is different than sizeof(Derived), which leads to an error in the determining
the pointer to the index within the dynamic array of class Derived. When the memory, within the array is modified with an improper offset, it is only a matter of time until a memory fault is generated with anything other than a trivial example.
In the following code, a context was created in a manner to reproduce the memory fault within the question. In the comments, you will see where the assignment was replaced with one that uses a dynamic_cast operation. The dynamic_cast now allows the index offsets to be correctly computed. Further, note the use of the dynamic_cast operations throughout, and the handling of the assignment operator. Caution is advised when using base pointers in this manner. See "Caution:" note at the end.
#include <iostream>
using namespace std;
class Base;
class Base{
public:
Base(){}
Base& operator=(Base& src){
copy_like_objects(this, &src);
return *this;
}
virtual void copy_like_objects(Base* dst, Base* src) = 0;
virtual ~Base(){};
};
class Derived : public Base{
public:
static const int objectAryLength = 10;
static int numObjects;
static Base* objectAry;
Derived();
~Derived(){};
static void newObject();
int data;
void copy_like_objects(Base *dst, Base *src){
*dynamic_cast<Derived*>(dst) = *dynamic_cast<Derived*>(src);
}
Derived& operator=(Derived& src){
data = src.data;
return *this;
}
static void allocate();
static void deallocate();
};
Derived :: Derived(){
data = -1;
}
void Derived :: allocate(){
if(objectAry == nullptr){
objectAry = new Derived[Derived :: objectAryLength];
}
for(int i = 0; i < Derived::objectAryLength; i++){ dynamic_cast<Derived*>(objectAry)[i].data = 0;}
}
void Derived :: deallocate(){
if(objectAry != nullptr){
delete[] dynamic_cast<Derived*>(objectAry);
objectAry = nullptr;
}
}
void Derived::newObject(){
Derived* tempObject = nullptr;
tempObject = new Derived; // The debugger may not step through
// the default constructor, which is called.
// tempObject = new Derived(); // Debugger steps through default constructor.
// At the time of this writing, in the commented statement
// the compiler seems to be computing the sizeof class base
// to evaluated the index into an array of the supposedly
// allocated array of bases classes instead of flagging as an error.
// As a result, The derived class copies data on a missaligned
// Derived object allocation, currupts the array of objects, which then
// is the cause of a subsequent memory fault.
//
// objectAry[numObjects] = *tempObject;
// Using the cast below, fixes the alignment issues and avoid a memory fault.
dynamic_cast<Derived*>(objectAry)[numObjects] = *tempObject;
numObjects++;
delete tempObject;
tempObject = nullptr;
}
int Derived::numObjects = 0;
Base* Derived::objectAry = 0;
int main(int argc, char **argv) {
Derived :: allocate();
for(int i = 0; i < Derived::objectAryLength; i++){
cout << (dynamic_cast<Derived*>(Derived::objectAry))[i].data << " : " ;
} cout << endl;
Derived::newObject();
Derived::newObject();
for(int i = 0; i < Derived::objectAryLength; i++){
cout << (dynamic_cast<Derived*>(Derived::objectAry))[i].data << " : " ;
} cout << endl;
Derived :: deallocate();
return 0;
}
Caution: In general, when base class pointers are used in this manner, one will create a situation where there is an high likelihood of making an error that causes a memory fault or an exception during a dynamic_cast<>, which can easily show up in run time edge cases. To resolve this issue, consider redesigning and start with:
Base** objectAry;
objectAry = new Base*[10];
The logic to manage the list can be placed in the Base class without knowledge of which derivations are stored within the list. This approach leverages the polymorphic nature of C++ and will simplify coding with improved reliability. This approach will allow any derived class of Base to be managed within the list. It is important to properly manage the allocation and deallocation of derived objects within the list management logic.
I have these kind of classes:
Game:
class Game {
private:
BoardField*** m_board_fields;
public:
Game() {
m_board_fields = new BoardField**[8];
for (int i = 0; i < 8; i++) {
m_board_fields[i] = new BoardField*[8];
}
}
Game::~Game() {
for (int i = 0; i < 8; i++) {
for (int j = 0; i < 8; j++) {
delete m_board_fields[i][j];
}
delete[] m_board_fields[i];
}
delete[] m_board_fields;
}
}
BoardField:
class BoardField {
private:
ChessPiece* m_piece;
....
public:
BoardField::~BoardField() {
delete m_piece;
}
}
And on the close of the program I get error in ~BordField:
Exception thrown: read access violation.
this was 0xFDFDFDFD.
Did I made my destructors incorrect? What is the best way to clear memory from multidimensional array ?
There is are two fundamental flaws in your design:
there is no clear ownership of the BoardFields: someone create it, someone else deletes it. It can work if you're very cautious but it's error prone.
you do not ensure the rule of 3 (or better 5): if you have any piece of code where you create a copy of either your Game or a of any BoardField the first object that gets destroyed will delete the m_piece pointer, and when the second object gets destroyed, it'll try to delete a second time the same pointer, which is UB.
There is a third important issue: you're over-using raw pointers:
if m_board_fields is a 2d array of fixed size, make it a fixed size array (aka BoardField* m_board_fields[8][8]). If you want to keep its size dynamic, use vectors.
a cell of m_board_field could be a pointer if there's some polymorphism expected. But this seems not the case here, as obviously ChessPiece is the polymorphic class. So better use plain fields instead of pointers (aka BoardField m_board_fields[8][8]).
Finally, instead of using raw pointer to ChessPiece, better use a shared_ptr<ChessPiece> : you don't have to worry about shallow pointer copies and double delete; the shared_ptr will take care of itself and destroy the object if it's no longer used.
I'm new to C++ and struggling to setup a proper class with private members and accessing them. Basically, I have a vector of Layers which make up a Stack. I'd like to create a simple function which simply adds a layer to the stack. I've tried to simplify this example to explain my problem.
// Stack.h
namespace NS {
class Stack
{
public:
Stack() {
}
virtual ~Stack() {
}
std::vector<Layer> const &getLayers() const;
virtual Layer* AddLayer(TextureBase texture);
protected:
std::vector<Layer> _layers;
}
This is my cpp file
//Stack.cpp
namespace NS {
std::vector<Layer> const &Stack::getLayers() const {
return _layers;
}
Layer* Stack::AddLayer(TextureBase texture) {
Layer* newLayer = new Layer();
newLayer->setTexture(texture);
std::vector<Layer> layerStack = Stack::getLayers();
layerStack.push_back(*newLayer);
return newLayer;
}
}
In my main file I create the stack and then try to add the layer like this:
auto myStack = getStack();
myStack->AddLayer(myTexture);
However, when I place a breakpoint after this line, myStack doesn't contain any layers (the size is 0). I can step through the AddLayer function and it does appear to add the Layer to the Stack... but perhaps it's not referencing the vector correctly. Can anyone provide some guidance as to why this is occurring?
The problem is that layerStack is a local copy of _layers:
std::vector<Layer> layerStack = Stack::getLayers();
You are pushing your new layer to this local copy, not to your data member. You need to take a reference to your data member instead:
std::vector<Layer>& layerStack = Stack::getLayers();
Alas, this won't compile because your getLayers function returns a const reference. You need to add a non-const counterpart:
std::vector<Layer>& getLayers();
There are 3 issues you have to address.
1. Layer* newLayer = new Layer() will dynamically allocate a Layer object, but when you insert it into your vector, you dereference it, so you end up doing a push_back on a COPY of your Layer object. You could have just used Layer newLayer = Layer(), or if I understand your intent correctly a vector of Layer pointers:
vector<Layer*> _layers;
In order to be editable, your getLayers() function must NOT return a const-ref to the _layers vector. Change it to std::vector& getLayers();
Finally, std::vector layerStack = Stack::getLayers(); creates a COPY of the vector returned by getLayers(). Change it to std::vector& layerStack = Stack::getLayers()
My class contains a unique pointer to an array. When the copy constructor is called, I want the class to create its own unique pointer array and just copy the contents of the old unique pointer array. I keep getting errors about converting from a const value, and I'm not sure how to get around it.
My pointer is declared under private like this:
std::unique_ptr<Manager[]> managers;
I planned to just loop through the array and copy manually, so I made this copy constructor:
Restaurant::Restaurant(const Restaurant &_r)
{
Manager *_managers = _r.managers;
for (int i = 0; i < MAX_MANAGERS; i++)
{
managers.get()[i] = _managers[i];
}
}
It gives the const convert error on this line:
Manager *_managers = _r.managers;
I just want to make a deep copy. How can I go about it to make this work?
The reason that it won't compile is that
_r.managers is of type std::unique_ptr<Manager[]>, but you want to initialize a raw pointer with this.
just change it to:
Restaurant::Restaurant(const Restaurant &_r)
{
for (int i = 0; i < MAX_MANAGERS; i++)
{
managers.get()[i] = _r.managers.get()[i];
}
}
or first take a smart pointer's data (which is an array)
Manager *_managers = _r.managers.get();
and then you can use it as was before:
for (int i = 0; i < MAX_MANAGERS; i++) {
managers.get()[i] = _managers[i];
}
In the line giving you an error, managers is an std::unique_ptr<Manager[]>. You're trying to assign it to a Manager*, which won't work.
You can fix it by taking the raw pointer of of the unique_ptr, for example:
Manager *_managers = _r.managers.get();
In order to copy the content of unique_ptr<>, you might want to use "deep copy", this means that you write copy constructor in class Manager and a clone function.
Example for copy constructor:
Manager(Manager const& manager) {
name = manager.name;
title = manager.title;
}
clone function:
unique_ptr<Manager> clone() const {
return make_unique<Manager>(*this);
}
I haven't been able to find a good answer to this question.
I'm working on a C++ program and I'm trying to implement a function named copy which takes a reference to another object as an argument. Then, it returns a deep copy of this object.
Some background on my project: the Scene class contains a dynamic array (called "Images") of pointers to either NULL or an instance of the Image class, which is not shown here - but works as it should (it inherits all of its methods from a third party library, EasyBMP)
The reason I'm doing this is to avoid duplicating code in two places, but it's very possible that I'm taking the wrong approach.
I call this function in my assignment operator:
Scene const & Scene::operator=(Scene const & source)
{
if (this != &source) {
clear();
copy(source);
}
return *this;
}
And my copy constructor:
Scene::Scene(Scene const & source)
{
copy(source);
}
Finally, my copy() method looks like this:
Scene const & Scene::copy(Scene const & source)
{
Scene res(source.Max);
for (int i=0; i<res.Max; i++)
{
delete res.Images[i];
if (source.Images[i] != NULL)
res.Images[i] = new Image(*(source.Images[i]));
else
res.Images[i] = NULL;
}
return res;
}
Currently, it does NOT work. One problem I can see is that I'm trying to return a variable that goes out of scope as soon as the copy function ends. I tried returning a reference before, but the compiler threw errors and this wouldn't help with the scope issue anyways.
But I'm not even sure that my logic is right, i.e. can you even do something like this in a constructor? Or should I just explicitly write out the code in the copy constructor and assignment operator (without implementing the helper method copy)?
I'm very new to C++ and pointers, so any guidance would be much appreciated.
There's a way easier and more idiomatic way to do what you want: the copy-and-swap idiom.
// N.B. Not tested, but shows the basic structure of the copy-and-swap idiom.
class Scene
{
public:
Scene(int)
{
// Initialize a pointer array of Images
}
~Scene()
{
// Get rid of our pointer array of Images
}
// Copy constructor
// N.B. Not exception safe!
Scene(const Scene& rhs) : imgPtrArray(new Image*[rhs.max])
{
// Perform deep copy of rhs
for (int i=0; i < rhs.max; ++i)
{
if (rhs.imgPtrArray[i] != 0)
imgPtrArray[i] = new Image(*(rhs.imgPtrArray[i]));
else
imgPtrArray[i] = 0;
}
}
// Copy assignment constructor
// When this is called, a temporary copy of Scene called rhs will be made.
// The above copy constructor will then be called. We then swap the
// members so that this Scene will have the copy and the temporary
// will destroy what we had.
Scene& operator=(Scene rhs)
{
swap(rhs);
return *this;
}
void swap(Scene& rhs)
{
// You can also use std::swap() on imgPtrArray
// and max.
Images** temp = imgPtrArray;
imgPtrArray = rhs.imgPtrArray;
rhs.imgPtrArray = temp;
int maxTemp = max;
max = rhs.max;
rhs.max = maxTemp;
}
private:
Images** imgPtrArray;
int max;
};
That being said, I highly recommend that you pick up a good introductory C++ book, which will cover the basics of implementing the copy constructor and copy assignment operators correctly.
Scene const & Scene::operator=(Scene const & source);
overloaded assignment operator copies the content of this to the argument received source. For copy there is no need to return any thing or to create a local object. Just make a member wise copy from this to source.
void Scene::copy(Scene const & source){
// Member wise copy from this to source
}
Rule of three should be helpful to better understand more about these.