在容器类中使用带有shared_ptr / unique_ptr的虚拟对象

时间:2017-12-05 18:25:55

标签: c++ c++14 virtual shared-ptr unique-ptr

我是C ++的新手(来自Java / PHP)。基本上,我需要创建一个容器类,它将包含一个指向虚拟类实例(Base类)的唯一/共享指针的引用。我无法编译这段代码(我正在使用MSVC 2015)。

编译错误是:

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

以下是重现此问题的示例应用程序:

#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;
}

请咨询

1 个答案:

答案 0 :(得分:0)

您应该考虑对象所有权以及对象所在的位置(堆栈或堆),这些都不是您在Java中必须关注的。

因为ContainerUnique有一个unique_ptr成员,我推断它的目的是拥有指向的对象。它有义务删除它。这与其余部分不一致,因为derived1在堆栈上,所以不需要被任何东西拥有,也不能删除。相反,假设我们在堆上创建了derived1

auto derived1 = std::make_unique<Derived>();

在堆上创建它,以便它需要管理,并通过将其指针存储在unique_ptr中来识别我们拥有该对象。要使用unique_ptr转让所有权,我们必须调整界面:

// Interface
void ContainerUnique::assignPtr(std::unique_ptr<Base> instance);
// Call site
cu.assignPtr(std::move(derived1));

如果我们采用原始引用或指针,则接口或调用站点中没有任何内容可以反映所有权的预期更改。如果我们采用引用到Base,并调用std::make_unique我们正在制作副本,并制作Base的副本(丢失任何派生数据)。采用unique_ptr可能是沟通所有权转移的最明确方式。

把它放在一起:

#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();
}