3

I have the following minimal reproducible example where it seems that my unique-pointer-containing object B is not allowed to contain a unique pointer to another instance of B:

#include <iostream>
#include <memory>

struct C {
  virtual void say_name() = 0;
};

struct A : public C {
  int value;
  A(int value) : value(value) {}
  void say_name() override { std::cout << "A" << value << std::endl; }
};

struct B : public C {
  std::unique_ptr<C> ptr;
  B(std::unique_ptr<C> ptr) : ptr(std::move(ptr)) {}
  void say_name() override { std::cout << "B" << std::endl; }
};

int main() {
  A a(5);
  B b(std::make_unique<A>(10));
  // Here I create another B - causes error
  B b2(std::make_unique<B>(b));
}

I expected the following to happen:

I expected b to own a, and b2 to own b which owns a.

However, I get an error message when I try and create b2 that says I have a call to an implicitly deleted copy-constructor of B.

I don't understand the error or how to fix it and want to understand how I should restructure my program so that I can nest objects in this way.

Here is the full error message:

In template: call to implicitly-deleted copy constructor of 'B'clang(ovl_deleted_special_init)
unique_ptr.h(767, 30): Error occurred here
main.cpp(33, 13): In instantiation of function template specialization 'std::make_unique<B, B &, 0>' requested here
main.cpp(24, 22): Copy constructor of 'B' is implicitly deleted because field 'ptr' has a deleted copy constructor
unique_ptr.h(221, 55): Copy constructor is implicitly deleted because 'unique_ptr<C>' has a user-declared move constructor
10
  • 3
    std::make_unique<B>(b) attempts to call the copy-constructor of B which is deleted because of the std::unique_ptr member which is non-copyable. Commented Mar 17 at 16:10
  • @3CxEZiVlQ added Commented Mar 17 at 16:12
  • 1
    Missing virtual destructor means UB Commented Mar 17 at 16:12
  • @wohlstad how can I restructure my program to escape this issue? In that case I cannot use unique pointers to point to my polymorphic classes. So is it necessary to use raw pointers? Commented Mar 17 at 16:12
  • 2
    The reason is explicitly mentioned in the error message, Copy constructor of 'B' is implicitly deleted because field 'ptr' has a deleted copy constructor. C++ doesn't get much clearer than this. Commented Mar 17 at 16:12

1 Answer 1

5

Problem is this expression:

std::make_unique<B>(b)

It attempts to create a copy of b.

Since B contains uniqe_ptr B is not copyable it is only moveable. So one way to fix it is to move b.

B b2(std::make_unique<B>(std::move(b)));

https://godbolt.org/z/qGGe1qv8Y

Other way to approach this it to provide own version of copy constructor. Problem is to archive this you need a way to duplicate ptr member variable. This can be done by adding functionality to C called clone:

#include <iostream>
#include <memory>

struct C {
    virtual void say_name() = 0;
    virtual std::unique_ptr<C> clone() const = 0;
    
    virtual ~C() = default;
};

struct A : public C {
    int value;
    A(int value)
        : value(value)
    {
    }
    void say_name() override { std::cout << "A" << value << std::endl; }

    std::unique_ptr<C> clone() const override {
        return std::make_unique<A>(value);
    }
};

struct B : public C {
    std::unique_ptr<C> ptr;
    B(std::unique_ptr<C> ptr)
        : ptr(std::move(ptr))
    {
    }
    B(const B& other) : ptr{other.ptr->clone()} {
    }
    void say_name() override { std::cout << "B" << std::endl; }
    std::unique_ptr<C> clone() const override {
        return std::make_unique<B>(*this);
    }
};

int main()
{
    A a(5);
    B b(std::make_unique<A>(10));
    B b2(std::make_unique<B>(b));
}

https://godbolt.org/z/eM663Yf1z

Depending on what you wish to achieve you have to select proper solution.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.