包含多态类包装的值语义:如何避免复制到const-ref

时间:2018-01-28 02:16:48

标签: c++ c++11 polymorphism

我有一个共同的抽象超类Base,有各种Derived类。为方便起见,我希望能够将基类作为值进行操作,而不是通过指针进行操作。我可以通过使用in this answer描述的技术创建Wrapper来实现此目的。 Wrapper存储unique_ptr<Base>并转发对该指针的方法调用,并具有允许我执行的适当构造函数

Derived derived;
Wrapper wrap = derived;
wrap.callMethodOnDerived();

因此用户可以在不考虑底层指针的情况下传递,返回和存储WrapperBase仍然完全隐藏。

然而,当他们不需要时,最终会创建副本。即

void fun(const Wrapper&);

fun(derived);                  // makes copy
const Wrapper& view = derived; // makes copy

将调用Wrapper(const Derived&)转换构造函数,然后将引用传递给它。相反,我希望创建一个指向原始对象的const Wrapper&,而不进行复制。我怎么能这样做?

#include <memory>

using BigVal = int; // Could be some expensive-to-copy type
using namespace std;

struct Base{
    Base(BigVal x) : value(x){
    }

    unique_ptr<Base> clone() const{
        return make_unique<Base>(value);
    }

    BigVal getValue() const{
        return value;
    }
protected:
    BigVal value;
};

struct Derived : public Base{
    Derived(BigVal x) : Base(x){
    }
};

struct Wrapper{
    unique_ptr<Base> ptr_;

    BigVal getValue() const{
        return ptr_->getValue();
    }

    // Ignore missing copy/move assignment operators
    Wrapper(const Wrapper& other){ 
        ptr_ = other.ptr_->clone();
    }

    Wrapper(Wrapper&& other){ 
        ptr_ = move(other.ptr_);
    }

    Wrapper(const Base& other){
        ptr_ = other.clone();
    }  

    Wrapper(Base&& other){
        ptr_ = make_unique<Base>(std::move(other));
    } 
};

void constFun(const Wrapper& t){
    cout<<"Const fun "<<t.getValue()<<endl;
}

int main()
{
    Base b1(1);
    Base b2(2);
    Derived d1(3);

    Wrapper w = d1; // copies

    Wrapper w2 = move(w); // moves
    Wrapper w3 = move(b1); // moves

    // No copy, just taking a reference:
    const Wrapper& w4 = w2; 
    constFun(w2);

    // Can I avoid a copy here?
    const Wrapper& w5 = b2;
    constFun(b2); 
}

我试图改变转换形式的构造函数

Base::operator const Wrapper& (){ 
  // return 'view' on this object
} 

但这会在执行Wrapper w = Derived();

时产生歧义

另一种选择可能是让Wrapper永远不会复制,除非你打电话给clone,或者在改变时懒洋洋地复制。另一个是一个独立的WrapperView类,用于代替const Wrapper&。但有没有办法在分配期间正常复制,但在创建引用时却没有?如果没有,其他可能性的优缺点是什么?

0 个答案:

没有答案