I have an abstract class and two concrete subclasses (Store), both with a pointer to another concrete subclass which is derived from an abstract class (Factory). Below is the code for the Store. I wanted to prevent memory leaks, so I started to write the copy control. I can't instantiate a new Factory however, because I don't know upfront what type it will be. What is a good practice to circumvent this? I could write the copy control in the concrete Stores, but then I have duplicate code.
I also tried to work with smart pointers instead, but there I find another difficulty. The snippet myFactory = std::make_shared<AbstractFactory>(ConcreteFactoryA()); apparently creates an AbstractFactory first, and then fills it with a ConcreteFactoryA. However, as the name suggests, AbstractFactory cannot be instantiated, as the compiler is telling me. Can you use shared_ptrs with abstract classes?
Code with plain pointers:
#pragma once
#include "AbstractFactory.h"
class AbstractStore
{
public:
// Copy control
AbstractStore(const AbstractStore& orig) : myFactory(new AbstractFactory(orig.myFactory)) {}
AbstractStore& operator=(const AbstractStore& orig) { return *this; } // TODO
~AbstractStore(void) {}
protected:
// Constructor
AbstractStore(void) {}
// Data members
AbstractFactory* myFactory;
};
class ConcreteStoreA : public AbstractStore
{
public:
ConcreteStoreA(void) { myFactory = new ConcreteFactoryA; }
~ConcreteStoreA(void) {}
};
class ConcreteStoreB : public AbstractStore
{
public:
ConcreteStoreB(void) { myFactory = new ConcreteFactoryB; }
~ConcreteStoreB(void) {}
};
Code with smart pointers:
#pragma once
#include "AbstractFactory.h"
#include <memory>
class AbstractStore
{
public:
// Copy control
AbstractStore(const AbstractStore& orig) : myFactory(orig.myFactory) {}
AbstractStore& operator=(const AbstractStore& orig) { myFactory = orig.myFactory; return *this; }
~AbstractStore(void) {}
protected:
// Constructor
AbstractStore(void) {}
// Data members
std::shared_ptr<AbstractFactory> myFactory;
};
class ConcreteStoreA : public AbstractStore
{
public:
ConcreteStoreA(void) { myFactory = std::make_shared<AbstractFactory>(ConcreteFactoryA()); }
~ConcreteStoreA(void) {}
};
class ConcreteStoreB : public AbstractStore
{
public:
ConcreteStoreB(void) { myFactory = std::make_shared<AbstractFactory>(ConcreteFactoryB()); }
~ConcreteStoreB(void) {}
};
You are not using make_shared correctly. Use:
std::make_shared<ConcreteFactory>();
You call it without any arguments here. make_shared is not accepting a constructed object but the arguments that are forwarded to it's constructor. In your case you would be forwarding to the copy constructor, which works poorly with abstract hierarchies. If you want copyable objects in hierarchies, use clone member functions with covariant return types.
This will return a shared_ptr<ConcreteFactory> which will be converted to shared_ptr<AbstractFactory> in the assignment (see (9) here. Also, use constructor initializer lists and virtual destructors.
You probably want one of these two things to make your smart pointer approach work:
Make ConcreteFactoryA and ConcreteFactoryB return a std::shared_ptr<AbstractFactory> or std::unique_ptr<AbstractFactory>. Simply assign, or better yet, initialize, in your "Store" classes
Initialize your shared_ptr<>s from raw pointers using std::shared_ptr<>::reset or the constructor
You would normally only use std::make_shared<> with smart pointers where you use new with raw pointers. In your case, you are simply assigning the pointer, so you shouldn't use it.
Related
I want to have a unique_ptr as a class variable to support polymorphism. I have the class built but I cannot use the std::vector constructor because the std::unique_ptr copy constructor is explicitely deleted. Here's an abstracted example:
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Animal {
protected:
std::string noise = "None";
public:
Animal() = default;
virtual std::string getNoise() {
return noise;
}
};
class Duck : public Animal {
public:
Duck() {
noise = "Quack!";
}
};
class Dog : public Animal {
public:
Dog() {
noise = "Woof!";
}
};
typedef std::unique_ptr<Animal> AnimalPtr;
class Zoo {
public:
AnimalPtr animalPtr;
explicit Zoo(AnimalPtr animalPtr) : animalPtr(std::move(animalPtr)){};
explicit Zoo(const Animal& animal) : animalPtr(std::make_unique<Animal>(animal)){};
const AnimalPtr &getAnimalPtr() const {
return animalPtr;
}
};
int main() {
Zoo zoo1((Dog()));
Zoo zoo2((Duck()));
std::vector<Zoo> zoos = {zoo1, zoo2}; // error, Call to implicitly-deleted copy constructor of 'const Zoo'
return 0;
};
I could solve this problem by using a std::shared_ptr instead, but something tells me this isn't the correct reason for allowing shared ownership. So my question is what is the correct way to solve this problem? (i.e. to allow me to construct a std::vector of animals.
Since C++11, a std::vector can perfectly accommodate an object that can't be copied. However not all methods of the vector can be used. In particular the initializer_list constructor that you are invoking to initialize your vector, do not allow them which is conter-intuitive, I admit. In current standard intializer_list always work by copy and never by move, this may change later I suppose. Here is the constructor signature:
vector(std::initializer_list<T> init, const Allocator& alloc = Allocator());
In anycase, by not wrapping zoo1 and zoo2 by std::move you asked it to do a copy of zoo1 and zoo2 anyway to build the std::initializer_object
However you can still use the default constructor that do not require the value to be copyable, and then do some push_backs, like
std::vector<Zoo> zoos;
zoos.push_back(std::move(zoo1));
zoos.push_back(std::move(zoo2));
As mentionned in rustyx answer on can also use emplace_back to directly build your Zoo object from any Animal in place inside the vector instead of moving an already built Zoo inside
class Zoo {
public:
AnimalPtr animalPtr;
explicit Zoo(AnimalPtr animalPtr) : animalPtr(std::move(animalPtr)) {};
explicit Zoo(const Animal& animal) : animalPtr(std::make_unique<Animal>(animal)) {};
Zoo(const Zoo& obj) : animalPtr(make_unique<Animal>(*obj.animalPtr)) {}
const AnimalPtr &getAnimalPtr() const {
return animalPtr;
}
};
If you declare the copy constructor like mentioned above then the file would compile successfully keeping the bellow statement intact.
std::vector<Zoo> zoos = { zoo1, zoo2 };
The problem is that initializer-list in vector construction makes copies because initializer-list passes elements by a const-reference.
You can bypass it by adding elements manually:
std::vector<Zoo> zoos;
zoos.emplace_back(Dog());
zoos.emplace_back(Duck());
Since ownership of animal pointers is Zoo class (one unique owner). It does not really make sense to "copy construct" a vector of Zoos (You would have to move the Zoo instances into the vector).
Why not simply declaring:
std::vector<Zoo*> zoos = {&zoo1, &zoo2};
In Qt, most classes usually have a public wrapper class with a single pointer to a private class. This is for binary compatibility.
https://wiki.qt.io/D-Pointer
However this means that there are a lot of things that need to be implemented by hand. Some people suggest using a QScopedPointer.
How to use the Qt's PIMPL idiom?
However, this does not implement copy and assignment either. Isn't there a smart pointer that will just copy the content of the pointer when it's copied. In essence, it should behaves as if the data in the private class were in the public class.
Qt offers a class just for this purpose: QSharedDataPointer
Used with QSharedData it offers a fast way to implement a class with implicitly shared data and copy on write behavior.
You can also do explicit sharing with QExplicitlySharedDataPointer.
class MyData : public QSharedData
{
public:
MyData (){ }
MyData (const MyData &other)
: QSharedData(other), a(other.a), b(other.b) { }
~MyData () { }
int a;
QString b;
};
class MyClass
{
public:
MyClass() { d = new MyData; }
MyClass(const MyClass&other)
: d (other.d)
{
}
void setA(int a) { d->a = a; } // the function is non const, so accessing d->a will make a copy of MyData if d is shared with another instance (CoW)
int a() const { return d->a; }
private:
QSharedDataPointer<MyData> d;
};
The QScopePointer is the equivalent of the std::unique_ptr, it's a pointer with unique ownership, meaning that it can not be copied.
What usually you do is a deep copy of what the ScopedPointer is pointing to when you implement the copy operation of the facade.
Another solution is to have the pimpl implemented with a shared pointer (QSharedPointer) ; but that means that a facade copied from another will point point to the same pimpl. In some scenarios that can be relevant.
I have a base class and several derived classes. The base class looks like this:
class Base
{
int type; //the derived type the object belongs to
int nOfChildren;
Base** children; //each child can be any of the derived types
...
}
Now I need to duplicate an instance of Base. Because of the recursion, a virtual method Base::duplicate() is needed. It also seems clear what should go in it:
Base temp = new Base();
temp->type = temp;
temp->nOfChildren = nOfChildren;
temp->children = new Base*[nOfChildren];
beyond that, it's not so clear.
Do I allocate each temp->children[i] as a Base object or as a derived object? Do I need a case statement to cater to all possible derived types? Do I need to implement a duplicate() method for each derived type, even those that contain no other information than the Base class? (If a derived class contains more information, then it is clear that I need a separate mechanism. There are several derived classes that contain no further data than the base, although they contain different implementations of a handler() method not shown.)
You are right, a virtual method is needed for cloning the polymorphic object. OTOH, you can leverage C++ features to simplify writing it:
class Child : public ICloneable {
public:
// stuff...
Child *clone() const { return new Child(*this); }
}
Also, don't put collections of objects into arrays! Use std::vector instead.
class Base
{
// stuff...
std::vector<Base*> children;
}
Even better, use a smart pointer to wrap the cloning operation into an object std::vector will be able to manage transparently.
template<typename T>
struct clone_ptr {
T *object;
clone_ptr() : object(new T()) {}
clone_ptr(T *object_) : object(object_) {}
clone_ptr(clone_ptr<T> const &other) : object(other.object->clone()) {}
clone_ptr<T> &operator=(clone_ptr<T> other) {
std::swap(object, other.object);
return *this;
}
~clone_ptr() { delete object; }
};
That way you can just use a std::vector of clone_ptrs into your Base:
class Base
{
// stuff...
std::vector<clone_ptr<Base>> children;
}
Each object will be automagically copied into an object of the same polymorphic type, as long as you implement clone() in each class. The vector will be cloned in the same way other data members are, automatically by the C++ compiler.
Suppose we have an Abstract class and child (derived from abstract) classes. I know we can instantiate from derivedClass like this:
AbstractBase *foo = new DerivedClass1();
But, is this the right way to define the top line code:
AbstractBase foo = *(new DerivedClass1());
I don't want to declare the Abstract class via pointer. But, What is the best way to do this and manage the memeory leak?
Thanks a lot
AbstractBase foo = *(new DerivedClass1()); will try to construct an instance of AbstractBase (which you can't do, it's abstract) using a constructor which takes an object of type DerivedClass1 (or something it's convertible to.
If you don't want to end up with a pointer to AbstractBase, but you do want to use new to allocate the object dynamically, then you probably want:
AbstractBase& foo = *(new DerivedClass1());
to define a reference to AbstractBase from your new DerivedClass1
Here is a very simple example of how to "chain" copy constructors. Note that the syntax may be a bit off, but this is the general idea:
class ABase {
public:
ABase(const ABase& ab) {
basevar = ab.getBasevar();
}
int getBasevar() { return basevar; }
private:
int basevar;
};
class c1 : public ABase {
public:
c1(const c1& c) : ABase(c) {
cvar = c.getCvar();
}
private:
int cvar;
};
In particular, note the use of the : operator between the function declaration and definition; this space allows for multiple direct assignments in a constructor function (possibly in other functions as well) and its content is called an "initialization list". Note also this answer which details some more examples.
I was wondering how to do something in C++. I want to be able to create an instance of this struct
struct ComplexInstruction : simple_instr
{
bool isHead;
bool isTail;
};
that copies all the data from the simple_instr instance. So essentially, I want to do something like this
ComplexInstruction cInstr = instr; // <- instance of simple_instr
and have cInstr have a copy of all the data in instr without having to copy over every field (since there's alot of them). I'm not sure how do this, and I don't think simple casting will work. Additionally, is it possible to do the reverse? I.e. have an instance of ComplexInstruction and turn it into an instance of simple_instr. I assume this can be done using casting, but I don;t have alot of experience with c++
Thanks in advance
Create a consctructor in the derived class to initialize from a base class.
class Base
{
int x;
public:
Base(int a) : x(a){}
};
class Derived : public Base
{
public:
Derived(const Base & B) : Base(B){}
};
Note that if you have a derived object of Base, you actually have a base object and you can safely use the base copy ctor like so.
Derived d;
Base b(d);//the parts of Base that are in Derived are now copied from d to b.
//Rest is ignored.
If you want to be more verbose, you write an operator= in your derived class like
void operator=(const Base & b)
{
Base::operator=(b);
//don't forget to initialize the rest of the derived members after this, though.
}
It all depends on what you want to do, really. The important thing is: be explicit. Don't leave uninitialized members of your class.
You need to provide a constructor that takes an argument that is convertible to const simple_instr&:
struct simple_instr {
int i;
simple_instr(): i(0) { }
explicit simple_instr(int i): i(i) { }
};
struct ComplexInstruction: simple_instr {
explicit ComplexInstruction(const simple_instr& simple):
simple_instr(simple), isHead(false), isTail(false) { }
bool isHead;
bool isTail;
};
int main() {
simple_instr instr;
ComplexInstruction cInstr(instr);
}
Here I chose an explicit constructor, but depending on the semantics, an implicit one could also be appropriate. Only if the constructor is implicit, the =-style initialization works without casting.
Edit: This is not the best way to accomplish this, please look at the other answers.
This will do what you are looking for.
struct ComplexInstruction : simple_instr
{
ComplexInstruction(const simple_instr &simple)
{
*((simple_instr*)this) = simple;
}
bool isHead;
bool isTail;
};
Then ComplexInstruciton complex = simple; will call the conversion constructor. ComplexInstruction's copy construct casts this to its base class and the = will call simple_instr's copy constructor, which by default is a bitwise copy.