最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - Can an object that owns a unique pointer be unique pointed to? - Stack Overflow

programmeradmin6浏览0评论

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

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
Share Improve this question edited Mar 17 at 16:11 Featherball asked Mar 17 at 16:06 FeatherballFeatherball 2171 silver badge9 bronze badges 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. – wohlstad Commented Mar 17 at 16:10
  • @3CxEZiVlQ added – Featherball Commented Mar 17 at 16:12
  • 1 Missing virtual destructor means UB – Marek R 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? – Featherball 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. – Pepijn Kramer Commented Mar 17 at 16:12
 |  Show 5 more comments

1 Answer 1

Reset to default 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./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./z/eM663Yf1z

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

发布评论

评论列表(0)

  1. 暂无评论