【问题标题】:Is it possible to adapt the "Prototype pattern" to rvalue references?是否可以使“原型模式”适应右值引用?
【发布时间】:2012-07-15 21:54:25
【问题描述】:

我有一个实现Prototype pattern 的类层次结构,我想使用移动语义来限制对象的深度复制。我尝试使用move() 成员函数来调整模式,这意味着我不再需要原始对象。这是我目前所拥有的:

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

当我运行它时,它表明使用了好的构造函数:

derived1::derived1()
derived2::derived2()
derived1::derived1(const derived1&)
derived2::derived2(const derived2&)
derived1::derived1()
derived1::derived1(derived1&&)
derived2::derived2()
derived2::derived2(derived2&&)

到目前为止,看起来不错。我只是不确定这是否是右值引用的标准兼容用法。有没有一点我没有想到会产生不良结果?

【问题讨论】:

  • 听起来像是 function ref-qualifiers 的工作。到目前为止,我认为只能在 clang 中使用。
  • @R.MartinhoFernandes 这看起来是一个有趣的功能,但我不明白你的意思。在我的情况下应该如何使用?
  • 您可以为左值和右值重载clone(),而不是使用具有不同名称的函数。
  • 如果你通过指针传递这些东西,你为什么需要这个移动函数?如果你不通过指针传递它们,这些东西如何被传递并且仍然是多态类型?
  • 是的,它工作正常。我刚刚提到了 ref-qualifiers,因为它们更通用:你可以让 std::forward&lt;T&gt;(obj).clone() 之类的东西毫不费力地工作,因为你不需要关心 obj 是作为左值还是右值引用转发来选择克隆函数.

标签: c++ design-patterns c++11 rvalue-reference move-semantics


【解决方案1】:

对于重复的方法定义,我更喜欢CRTP。对于您的情况,我会声明如下:

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

在实现类时:

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 */
};

顺便说一句,您可能希望返回 shared_ptr 对象而不是原始指针。这通常是可克隆类型而不是 unique_ptr 的情况。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-01
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 2023-01-09
    相关资源
    最近更新 更多