考虑以下持有共享资源的类的简化示例:
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.
有点麻烦,而且比这更糟糕:不是你所期望的。
我应该如何处理这种歧义?