I am fairly new to C++ (coming from Java/PHP). Basically, I need to create a container class that will hold a reference of a unique/shared pointer to a virtual class instance (Base class). I am unable to get this piece of code to compile (I am using MSVC 2015).
The compiler error is:
error C2280: 'std::unique_ptr<Base,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
Here is a sample application to reproduce the issue:
#include <iostream>
#include <memory>
class Base {
public:
virtual void foo() const = 0;
virtual void bar() const = 0;
};
class Derived : public Base {
public:
void foo() const override {
std::cout << "foo" << std::endl;
};
void bar() const override{
std::cout << "bar" << std::endl;
};
};
class ContainerUnique {
public:
ContainerUnique() {
ptr = nullptr;
}
void assignPtr(const Base &instance) {
auto ptr = std::make_unique<Base>(instance);
ptr.swap(ptr);
};
std::unique_ptr<Base> getPtr() {
return ptr;
};
private:
std::unique_ptr<Base> ptr;
};
class ContainerShared {
public:
ContainerShared() {
ptr = nullptr;
}
void assignPtr(const Base &instance) {
auto ptr = std::make_shared<Base>(instance);
ptr.swap(ptr);
};
std::shared_ptr<Base> getPtr() {
return ptr;
};
private:
std::shared_ptr<Base> ptr;
};
int main() {
Derived derived1 = Derived();
Derived derived2 = Derived();
ContainerUnique cu = ContainerUnique();
ContainerShared cs = ContainerShared();
cu.assignPtr(derived1);
cs.assignPtr(derived2);
std::unique_ptr<Base> uptr = cu.getPtr();
std::shared_ptr<Base> sptr = cs.getPtr();
return 0;
}
Please advice
You should think about object ownership, and where objects live (stack or heap), neither of which you may have had to focus on in Java.
Because ContainerUnique has a unique_ptr member, I infer that it is intended to own the pointed-to object. It is being given the obligation to delete it. This is inconsistent with the rest, because derived1 is on the stack, so has no need to be owned by anything, and cannot be deleted. Instead, suppose we created derived1 on the heap:
auto derived1 = std::make_unique<Derived>();
That creates it on the heap, so that it needs managing, and identifies us as owning the object by storing its pointer in a unique_ptr. To transfer ownership with a unique_ptr, we have to tweak the interface:
// Interface
void ContainerUnique::assignPtr(std::unique_ptr<Base> instance);
// Call site
cu.assignPtr(std::move(derived1));
If we take a raw reference or pointer, there is nothing in the interface or the call site to reflect the intended change in ownership. If we take a reference-to-Base, and call std::make_unique we are making a copy, and making a copy of a Base (losing any Derived data). Taking a unique_ptr is probably the clearest way to communicate ownership transfer.
Putting it together:
#include <memory>
struct Base {
virtual void foo() const = 0;
virtual void bar() const = 0;
};
struct Derived : Base {
void foo() const override { }
void bar() const override { }
};
class ContainerUnique {
public:
void assignPtr(std::unique_ptr<Base> instance) {
ptr.swap(instance);
};
std::unique_ptr<Base> getPtr() {
return std::move(ptr);
};
private:
std::unique_ptr<Base> ptr;
};
int main() {
auto derived1 = std::make_unique<Derived>();
auto cu = ContainerUnique();
cu.assignPtr(std::move(derived1));
auto uptr = cu.getPtr();
}
Related
I have an access to an external library that provides a function that returns a pointer to an abstract class Foo, I want to copy that class but the library is pre-compiled so I cannot add any new functions like the virtual clone function https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Virtual_Constructor.
Is there any other way to copy the contents of the pointer?
class Foo // private precompiled class I cannot add methods to
{
virtual void F() = 0;
};
class FooChild : public Foo
{
void F() override
{
}
};
static Foo* getFoo()
{
return new FooChild();
};
int main()
{
Foo* f = getFoo();
Foo* fCopy = new Foo(f); //cannot do that
return 0;
}
Your only option is a long if else if chain, based on typeid(*f), with a branch for every possible type.
Foo *copy = nullptr;
if (typeid(*f) == typeid(FooChild))
copy = new FooChild(static_cast<FooChild &>(*f));
else if // ... same for every child class
If you're not forced to use Foo in your main() there's a way to make this work if you use a FooBase subclass instead.
class Foo
{
public:
virtual ~Foo() = default;
virtual void f() = 0;
};
class FooBase: public Foo
{
public:
virtual FooBase* clone() = 0;
};
template <class Derived>
class FooBase_: public FooBase {
public:
FooBase* clone() override { return new Derived(static_cast<Derived&>(*this)); }
};
class FooChild1: public FooBase_<FooChild1> {
public:
FooChild1() = default;
FooChild1(const FooChild1&) = default;
void f() override { std::cout << "FooChild1\n"; }
};
class FooChild2: public FooBase_<FooChild2> {
public:
FooChild2() = default;
FooChild2(const FooChild2&) = default;
void f() override { std::cout << "FooChild2\n"; }
};
int main()
{
FooBase* f1 = new FooChild1;
FooBase* f1Copy = f1->clone();
f1->f();
f1Copy->f();
FooBase* f2 = new FooChild2;
f2->f();
delete f1;
delete f1Copy;
delete f2;
return 0;
}
FooBase_ is a CRTP generating a specific clone() method for each FooChildN concrete class, avoiding repetition.
Demo here: https://godbolt.org/z/nva75Gx4x
I'm trying to create an Object Reference template class that will hold class pointers and everything works except when trying to type cast base class ptr to a derived class ptr.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#define null nullptr
class BaseType;
class DerivedType;
template<class T>
class ObjRef {
public:
T *ptr = null; //should be private
ObjRef& operator= (T *ptr) { this->ptr = ptr; return *this; }
ObjRef& operator= (const ObjRef &ref) { ptr = ref.ptr; return *this; }
operator T*() const {return ptr;}
operator T() const {return *ptr;}
ObjRef() {}
ObjRef(const ObjRef ©) { ptr = copy.ptr; }
#ifdef VOID_FIX
ObjRef(void*p) { ptr = (T*)p; } //this could fix the bug except would not work with multiple inheritance and is not safe
#else
ObjRef(T*p) { ptr = p; }
#endif
~ObjRef() { }
T* operator->() const {return ptr;} //unfortunately operation. (dot) can not be overloaded - that would make life too easy :(
};
class Object {};
class BaseType : public Object {
public:
int baseValue;
};
class DerivedType : public BaseType {
public:
operator BaseType*() {return (BaseType*)this;} //helpful?
int derivedValue;
};
typedef ObjRef<BaseType> Base;
typedef ObjRef<DerivedType> Derived;
void func4(Base x) {
x->baseValue = 1;
}
void func5(Derived x) {
x->derivedValue = 1;
}
int main() {
Base b = null;
Derived d = null;
Base x;
x = d; //no type cast needed
func4((Base)d); //cast from Derived to Base class - no problem
b = d; //base does point to derived
// func5((Derived)b); //cast from Base to Derived - does not work (desired syntax)
// with gcc -fpermissive can be used to change error to warning - can I silence the warning ?
// what would cl.exe equivalent be?
// func5((Derived)b.ptr); //invalid cast, ptr should be private
// func5((DerivedType*)b); //invalid cast, ptr should be private
// func5(dynamic_cast<DerivedType*>(b.ptr)); //invalid cast, source type is not polymorphic, ptr should be private
func5((DerivedType*)b.ptr); //this works but is undesired and ptr should be private
func5(static_cast<DerivedType*>(b.ptr)); //works but again is undesired and ptr should be private
return 0;
}
In the example ObjRef<> is a template that holds a pointer to the class defined and is used as a new type. It works fine except for trying to cast base class to derived class. Look at how func5() is being called with a base class reference. The first attempt is the desired syntax. If I use the ptr inside the reference class it will work but that is undesired.
I just feel like I'm missing an operator or something.
Thanks.
As usual I found the solution just moments after posting.
The ObjRef<> class needs to know the base class.
Here is the new code:
#include <stdio.h>
#include <stdlib.h>
#define null nullptr
class BaseType;
class DerivedType;
template<class T>
class ObjRef {
public:
T *ptr = null;
ObjRef& operator= (auto *ptr) { this->ptr = ptr; return *this; }
ObjRef& operator= (const ObjRef<auto> &ref) { ptr = ref.ptr; return *this; }
operator T*() const {return ptr;}
ObjRef() {}
ObjRef(const ObjRef<auto> ©) { ptr = (T*)copy.ptr; }
ObjRef(T*p) { ptr = p; }
~ObjRef() { }
T* operator->() const {return ptr;} //unfortunately operator. (dot) can not be overloaded - that would make life too easy :(
};
class Object {};
class BaseType : public virtual Object {
public:
int baseValue;
};
class InterfaceType : public virtual Object {
public:
virtual void func7() {
printf("it works!\n");
};
};
typedef ObjRef<InterfaceType> Interface;
class DerivedType : public BaseType, public InterfaceType {
public:
int derivedValue;
};
typedef ObjRef<BaseType> Base;
typedef ObjRef<DerivedType> Derived;
void func4(Base x) {
x->baseValue = 1;
}
void func5(Derived x) {
x->derivedValue = 2;
}
void func6(Interface x) {
x->func7();
}
int main() {
Base b = new BaseType();
Derived d = new DerivedType();
Base x;
x = d; //no type cast needed
func4((Base)d); //cast from Derived to Base class - no problem
printf("BaseValue=%d\n", d->baseValue);
b = d; //base does point to derived
func5((Derived)b); //cast from Base to Derived - works now!
printf("DerivedValue=%d\n", d->derivedValue);
func6(d);
return 0;
}
UPDATE : Posted a new version that will work with any level of inheritance but now requires C++14 (auto keyword)
UPDATE #2 : Now uses a single ObjRef class (still requires C++14). Unfortunately cl.exe doesn't support 'auto' template parameters yet :(
UPDATE #3 : Added some test code to prove it works.
There are a lot of things that needs to be said. First off, I would like to know if the approach below is considered a design pattern or even a common technique (That's why I didnt provide further information on the title). If thats the case, whats the name?
Anyways, this is a minified version of what I'm trying to achieve. Since I need to use copying, I found that using std::shared_ptr is the best to avoid deallocated (deleted) pointers.
class Foo
{
public:
Foo() : ptr(nullptr) {}
Foo(const Foo& foo) : ptr(foo.ptr) {}
virtual ~Foo() = default;
void whatever() {
if (ptr)
ptr->whateverHandler();
}
void reset() {
ptr.reset();
}
void resetBar() {
ptr.reset(new Bar);
}
// Other resets here...
protected:
Foo(Foo* foo) : ptr(foo) {}
private:
// Every child class should override this
virtual void whateverHandler() {
throw "whateverHandler cant be called within base class";
}
protected:
std::shared_ptr<Foo> ptr;
};
class Bar : public Foo
{
public:
Bar() : Foo(this) {}
void whateverHandler() {
printf("Bar's handler!!! \n");
}
};
This all looks good and compiles fine, however, the following exame crashes. Why is that?
int main()
{
{
Foo f;
f.resetBar();
}
return getchar();
}
Bar() : Foo(this) {}
Be careful when you pass this to a shared_ptr.
Think about what will happen afterf.resetBar(); and ptr.reset(new Bar); again.
For new Bar, an object of type Bar will be constructed, and inside its constructor this is passed to the parent class member ptr, then the object is managed by the it which is a std::shared_ptr.
After that, the object is managed by f.ptr; which is another std::shared_ptr.
So there're two std::shared_ptrs pointing to the same object, but std::shared_ptrs don't know anything about that; because you're constructing them separately. When f and f.ptr is destroyed, the pointed-to object will be destroyed too. Then the member ptr will be destroyed, it will try to destroyed the same object again, which leads to UB.
I'm not sure about what the design trying to accomplish, but just stopping passing this to a std::shared_ptr could eliminate UB.
class Foo
{
public:
virtual ~Foo() = default;
void whatever() {
if (ptr)
ptr->whateverHandler();
}
void reset() {
ptr.reset();
}
void resetBar() {
ptr.reset(new Bar);
}
// Other resets here...
private:
// Every child class should override this
virtual void whateverHandler() = 0;
std::shared_ptr<Foo> ptr;
};
class Bar : public Foo
{
public:
void whateverHandler() {
printf("Bar's handler!!! \n");
}
};
int main()
{
{
Foo f;
f.resetBar();
f.whatever();
f.resetSthElse();
f.whatever();
}
}
And IMO, having a member of type std::shared_ptr pointing to derived class is confusing; separating it might be better. And then, I think it might be the bridge design partern.
class Foo
{
public:
void whatever() {
if (ptr)
ptr->whateverHandler();
}
void reset() {
ptr.reset();
}
void resetBar() {
ptr.reset(new BarHandler);
}
// Other resets here...
private:
std::shared_ptr<FooHandler> ptr;
};
class FooHandler
{
public:
virtual ~FooHandler() = default;
// Every child class should override this
virtual void whateverHandler() = 0;
};
class BarHandler : public FooHandler
{
public:
void whateverHandler() {
printf("Bar's handler!!! \n");
}
};
int main()
{
{
Foo f;
f.resetBar();
f.whatever();
f.resetSthElse();
f.whatever();
}
}
The Foo::ptr holds a pointer to its mother Foo(this) with reference count 1.
In Foo::resetBar(), when Foo asking Foo::ptr to call reset(new Bar), Foo::ptr gave up its ownership to its mother Foo(this) and found out the reference count was already decreased to 0, so it need to kill Foo.
When the Foo is dead, its children are killed. So Foo::ptr must be dead, too. Then assigning the new Bar to dead Foo::ptr causes UB.
I have been experimenting with abstract types.
The code below gives me a desired effect.
class base{
public:
virtual void do_stuff() = 0;
};
class derived: public base{
public:
void do_stuff(){/*stuff*/}
};
class manager{
vector<shared_ptr<base>> ptrs;
public:
void add(base* ptr){
ptrs.emplace_back(ptr);
}
};
manager foo;
foo.add(new derived());
Fine and dandy, but it's awkward because the user is not only dealing with pointers, but has to use new without ever calling delete. My question is if there's a way I can implement this where the user of manager doesn't ever have to deal with pointers or new.
foo.add(derived()); //example
My attempts to implement this end up as:
class manager{
vector<shared_ptr<base>> ptrs;
public:
void add(base& ref){
ptrs.emplace_back(&ref);
}
};
But, the compiler says no known conversion from 'derived' to 'base&'. I have no idea how to make a reference to base compatible with a reference to derived. How do I get around this?
Pass unique_ptr
Your add function takes ownership of this object. A safe way of passing ownership is to pass unique_ptr.
Using a unique_ptr is fairly flexible because you can construct a shared_ptr from a unique_ptr or if you change your mind in the future you can store the unique_ptr directly.
class manager{
vector<shared_ptr<base>> ptrs;
public:
void add(std::unique_ptr<base> ptr){
ptrs.emplace_back(std::move(ptr));
}
};
manager foo;
foo.add(std::make_unique<derived>());
Using a temporary std::unique_ptr you avoid the owning raw pointer that is not exception safe. By using make_unique you can avoid writing new.
Live demo.
Pass a Factory
Another option if the caller really doesn't want to have to deal with any kind of pointer is to pass some sort of Factory that the add function uses to construct the object. The Factory could simply be a static create function on the derived class itself:
using Factory = std::function<std::unique_ptr<base>()>;
class manager{
std::vector<std::shared_ptr<base>> ptrs;
public:
void addUsing(const Factory& factory){
ptrs.emplace_back(factory());
}
};
class derived : public base {
public:
...
static std::unique_ptr<derived> create() {
return std::make_unique<derived>();
}
};
manager foo;
foo.addUsing(derived::create);
Live demo.
You can let your add() function be passed the arguments to be used in the construction of type T, where T is specified as the type of a subclass.
template <typename T, typename... TArgs>
void add(TArgs&&... args)
{
ptrs.emplace_back(std::make_shared<T>(std::forward<TArgs>(args)...));
}
Which can then be called as follows:
bm.add<derived_a>( "hello" ); // derived_a constructor takes a string
bm.add<derived_b>( 42 ); // derived_b constructor takes an int
Full example
#include <string>
#include <vector>
#include <memory>
class base
{
public:
virtual void f() = 0;
};
class derived_a : public base
{
public:
derived_a( std::string const& s ) : s_{ s } {}
void f() override { std::cout << "derived_a::string = " << s_ << '\n'; }
private:
std::string s_;
};
class derived_b : public base
{
public:
derived_b( int i ) : i_{ i } {}
void f() override { std::cout << "derived_b::int = " << i_ << '\n'; }
private:
int i_;
};
class base_manager
{
public:
template <typename T, typename... TArgs>
void add( TArgs&&... args )
{
ptrs.emplace_back( std::make_shared<T>( std::forward<TArgs>( args )... ) );
}
void print() { for ( auto& d : ptrs ) d->f(); }
private:
std::vector<std::shared_ptr<base>> ptrs;
};
int main()
{
base_manager bm;
bm.add<derived_a>( "hello" );
bm.add<derived_b>( 42 );
bm.print();
}
You can't pass a temporary (an r-value) to a non-const reference. Also you try to take the address of that temporary object, which will in the end produce a dangling pointer and undefined behavior.
Assuming you want to pass an object of unknown runtime type to the manager:
One thing you can do is using some sort of polymorphic copy mechanism (like a virtual clone method) and make an internal copy of the object on the heap (it has to be polymorphic, to avoid object slicing).
class base {
public:
virtual void do_stuff() = 0;
virtual shared_ptr<base> clone() const = 0;
virtual ~base()=default;
};
class derived : public base {
int data;
public:
derived() :data(0) {};
derived(const derived& other) :data(other.data)
{};
virtual shared_ptr<base> clone() const override {
return make_shared<derived>(*this);
};
void do_stuff() {/*stuff*/ }
};
class manager {
vector<shared_ptr<base>> ptrs;
public:
void add(const base& obj) {
ptrs.emplace_back(obj.clone());
}
};
int main() {
manager foo;
foo.add(derived());
}
without the clone, it would look something like this:
void add(const base& obj) {
if (typeid(obj)== typeid(derived) ){
ptrs.emplace_back(make_shared<derived>(static_cast<const derived&>(obj)));
}
else if (typeid(obj) == typeid(derived2)) {
...
}
Your original question seems to be concerned over the fact that the user/caller creates a pointer and hands it off and never deletes it. My example below, simply makes it explicit to the user that he can hand it off and forget about it. In otherwords, require the user to pass a shared_ptr...
#include <stdlib.h>
#include <vector>
#include <memory>
using namespace std;
class base{
public:
virtual void do_stuff() = 0;
};
class derived : public base{
public:
void do_stuff(){/*stuff*/ }
};
class manager{
vector<shared_ptr<base>> ptrs;
public:
void add(shared_ptr<base> ptr){
ptrs.emplace_back(ptr);
}
};
int main()
{
manager foo;
shared_ptr<derived> bp(new derived()); //require the user supply a smart pointer
foo.add(bp);
return 0;
}
This is simpler than the other posts, and may not be as forward thinking, but it does not require the derived class to implement additional base members. In many cases, it is may be enough.
I have a hierarchie of classes that implement the Prototype pattern and I would like to use move semantics to limit objects deep copy. I tried to adapted the pattern with a move() member function which meaning is that I do not need the original object anymore. Here is what I have so far:
#include <iostream>
#include <utility>
#include <vector>
struct base
{
virtual ~base() { }
virtual base* clone() const = 0;
virtual base* move() = 0;
};
struct derived1 : public base
{
derived1() { std::cout << "derived1::derived1()\n"; }
derived1(const derived1&) { std::cout << "derived1::derived1(const derived1&)\n"; }
derived1(derived1&&) { std::cout << "derived1::derived1(derived1&&)\n"; }
virtual ~derived1() { }
virtual base* clone() const { return new derived1(*this); }
virtual base* move() { return new derived1(std::move(*this)); }
};
struct derived2 : public base
{
derived2() { std::cout << "derived2::derived2()\n"; }
derived2(const derived2&) { std::cout << "derived2::derived2(const derived2&)\n"; }
derived2(derived2&&) { std::cout << "derived2::derived2(derived2&&)\n"; }
virtual ~derived2() { }
virtual base* clone() const { return new derived2(*this); }
virtual base* move() { return new derived2(std::move(*this)); }
};
std::vector<base*> vec;
void foo(const base& obj)
{
vec.push_back(obj.clone());
}
void foo(base&& obj)
{
vec.push_back(obj.move());
}
int main()
{
derived1 d1;
derived2 d2;
foo(d1);
foo(d2);
foo(derived1());
foo(derived2());
}
When I run it, it show that the good constructors are used:
derived1::derived1()
derived2::derived2()
derived1::derived1(const derived1&)
derived2::derived2(const derived2&)
derived1::derived1()
derived1::derived1(derived1&&)
derived2::derived2()
derived2::derived2(derived2&&)
So far, it seems good. I am just not sure if this is a standard compliant usage of the rvalue references. Is there a point I did not think of that would produce undesirable results?
For recurring method definition I prefer CRTP. For your case I'd declare something like:
template<typename TDerived>
class virtually_clonable : public base
{
public:
virtual base* clone() override
{
return new TDerived(*AsDerived());
}
virtual base* move() override
{
return new TDerived(std::move(*AsDerived()));
}
private:
TDerived* AsDerived()
{
return static_cast<TDerived*>(this);
}
};
And while implementing the classes:
class derived1 : public virtually_clonable<derived1>
{
public:
/* your ctors goes here*/
/* no need to implement clone/move again */
};
class derived2 : public virtually_clonable<derived2>
{
public:
/* your ctors goes here*/
/* no need to implement clone/move again */
};
By the way you may want to return shared_ptr objects instead of raw pointers. That is usually the case for clonable types instead of unique_ptr.