使用什么类型的智能指针创建界面?

时间:2015-07-03 14:18:17

标签: c++ smart-pointers

我有一些代码生成这样的小部件:

std::unique_ptr<Widget1> Widget1::Create()
std::unique_ptr<Widget2> Widget2::Create()

现在我有另一段需要使用Widget1Widget2的代码。我希望它有一个类似的界面,但把小部件作为输入。

std::unique_ptr<Widget3> Widget3::Create(<?> Widget1, <?> Widget2)

在内部,Widget3应包含引用,例如

class Widget3
{
public:
   std::unique_ptr<Widget3> Create(<?> Widget1, <?> Widget2)
   {
      _widget1 = Widget1;
      _widget2 = Widget2;
   }
   void doSomething()
   {
      std::cout << _widget1->hello() << _widget2->hello();
   }
private:
   <?> _widget1, _widget2
};

现在我考虑过为std::shared_ptr使用<?>,因为这似乎是最明智的。但是......我对我应该如何传递它感到困惑?

思想?

2 个答案:

答案 0 :(得分:2)

这里的诀窍是“关注点分离”。

对象的生存期是其实现的一个单独问题。

shared_ptrunique_ptr控制生命周期。小部件 n 对象执行事物。

如果您尊重代码设计中的问题分离,那么您的生活将是幸福的,您的计划永远不会出错,您的同事也会爱你:

#include <iostream>
#include <memory>
#include <string>

struct Widget1 {
    std::string hello() { return "widget1"; }
};

struct Widget2 {
    std::string hello() { return "widget2"; }
};

struct Widget3 {
    // Widget3 objects share their components. This is now documented in the interface here...
    Widget3(std::shared_ptr<Widget1> widget1, std::shared_ptr<Widget2> widget2)
    : _widget1(std::move(widget1))
    , _widget2(std::move(widget2))
    {
    }

    void doSomething()
    {
        std::cout << _widget1->hello() << _widget2->hello();
    }
private:
    std::shared_ptr<Widget1> _widget1;
    std::shared_ptr<Widget2> _widget2;
};

using namespace std;

auto main() -> int
{
    // make a unique Widget3
    auto w1a = make_unique<Widget1>();
    auto w2a = make_unique<Widget2>();
    // note the automatic move-conversion from unique_ptr to shared_ptr
    auto w3a = make_unique<Widget3>(move(w1a), move(w2a));

    // make unique widget3 that uses shared components
    auto w1b = make_shared<Widget1>();
    auto w2b = make_shared<Widget2>();
    auto w3b = make_unique<Widget3>(w1b, w2b);

    // make shared widget3 that shares the same shared components as w3b
    auto w3c = make_shared<Widget3>(w1b, w2b);

    return 0;
}

使用static :: create函数是不必要的。它会在对象的创建者上强制执行内存模型。

如果要强制执行内存模型(例如始终创建共享指针),请使用shared-handle-pimpl习惯用法私有地执行此操作:

// Widget4 objects have shared-handle semantics.
struct Widget4
{
private:
    struct impl {
        std::string hello() const { return "hello4"; }
    };

public:
    Widget4()
    : _impl { std::make_shared<impl>() }
    {}

    std::string hello() const {
        return _impl->hello();
    }

private:
    std::shared_ptr<impl> _impl;
};

答案 1 :(得分:0)

如果Widget1和widget2仅作为widget3的成员存在,并且您不需要在以后独立引用这些变量,则可以将它们作为值传递给Widget3::create()

std::unique_ptr<Widget1> Widget1::Create()// returns a unique_ptr to widget1
std::unique_ptr<Widget2> Widget2::Create()// returns a unique_ptr to widget2

std::unique_ptr<Widget3> Create(std::unique_ptr<Widget1>  Widget1,
                                std::unique_ptr<Widget2>  Widget2)

否则,如果您希望将Widget1和Widget2的对象保留为Widget3的共享对象,请对widget1和widget2使用shared_ptr