3

考虑以下持有共享资源的类的简化示例:

class array
{
    typedef std::array<float, 1000> resource;

public:
    // default constructor, creates resource
    array() : p_(std::make_shared<resource>()), a_(0), b_(1000) {}

    // create view
    array operator()(int a, int b) { return array(p_, a_+a, a_+b); }

    // get element
    float& operator[](int i) { return (*p_)[a_+i]; }

private:
    std::shared_ptr<resource> p_;
    int a_, b_;

    // constructor for views
    array(std::shared_ptr<resource> p, int a, int b) : p_(p), a_(a), b_(b) {}
};

现在我想知道如何为这个类定义一个不会混淆其用户的语义。例如,我想允许operator=()复制元素:

array x, y;
x = y;                 // copies all elements from y's storage to x's
x(30,40) = y(50,60);   // copies 10 elements

但是,为了保持一致,复制构造函数和复制赋值运算符不应该总是复制吗?关于什么:

array z = x(80,90);    // will create an array referencing x's storage

在这种情况下,编译器将忽略副本,因此无论我的复制赋值运算符做什么,都将保存对的存储z的引用。x没有办法解决这个问题。

那么赋值总是创建引用并显式声明复制是否更有意义?例如,我可以定义一个 wrapper class copy_wrapper,对其进行赋值会强制复制元素:

class copy_wrapper
{
    array& a_;
public:
    explicit copy_wrapper(array& a) : a_(a) {}
    array& get() { return a_; }
};

class array
{
    // ...
    array& operator=(const array& a);    // references
    array& operator=(copy_wrapper c);    // copies
    copy_wrapper copy() { return copy_wrapper(*this); }
};

这将迫使用户编写:

array x, y;
x(30,40) = y(50,60).copy();  // ok, copies
x(30,40) = y(50,60);         // should this throw a runtime error?
x = y;                       // surprise! x's resource is destructed.

有点麻烦,而且比这更糟糕:不是你所期望的。

我应该如何处理这种歧义?

4

1 回答 1

1

赋值总是创建引用并显式声明复制是否更有意义?

在实践中,没有。期望开发人员记住a = b不会复制是std::auto_ptr陷入困境的原因。C++11 标准委员会还决定std::movestd::forward允许开发人员明确地说“我不是在复制”。

怎么样:array z = x(80,90);在这种情况下,编译器将忽略副本,因此无论我的复制赋值运算符做什么,z 都将持有对 x 存储的引用。没有办法解决这个问题。

这是你的赠品。您希望 "array" 和 "view to an array" 采取不同的行动,但您用 class 来表示它们array

实现一个arrayview具有类似公共接口的新类,并将范围a_和移动b_arrayview.

array x, y;
x = y;                  // "array = array" copies all elements
x(30,40) = y(50,60);    // "arrayview = arrayview" copies element range
arrayview v = x(80,90); // "arrayview(const arrayview&) shallow copies
x(30,40) = y;           // NOT DEFINED, since this has no clear meaning
array z = x(80,90);     // NOT DEFINED, since this has no clear meaning

请注意,在您的赋值运算符中,从具有相同资源的arrayview复制 应该是有效的,但在这种特定情况下,您应该检查是否需要而不是.arrayviewstd::copy_backwardstd::copy

于 2012-12-27T17:25:45.283 回答