防止复制构造和返回值引用的赋值

时间:2010-06-23 23:13:41

标签: c++ copy-constructor assignment-operator

如果我有一个函数返回对我无法控制其源的类实例的引用,请说list<int>

list<int>& f();

我想确保其值分配给另一个引用,例如:

list<int> &a_list = f();

如果用户改为:

list<int> a_list = f(); // note: no '&', so the list is copied

我希望它是一个编译时错误,因为用户只会操作列表的副本而不是原始列表(这绝对不是我的应用程序的目的/想要的东西)。

有没有办法防止上面的复制构造和赋值(比如通过某种“包装”类)?

理想情况下,如果要使用某个包装类,比如wrapper<T>,我希望它适用于任何类型T的对象。


是的,我知道对于我可以控制的类,我可以简单地使复制构造函数和赋值运算符private像:

class MyClass {
public:
    // ...
private:
    MyClass( MyClass const& );
    MyClass operator=( MyClass const& );
};

禁止复制和分配;但是,如上所示,我想为std::list执行此操作,我不能简单地创建复制构造函数和赋值运算符private

5 个答案:

答案 0 :(得分:2)

这是我之前的答案,因为问题已得到澄清。我之前的回答可能对有理智要求的人有用,所以我保持原样。

理想的行为是不可能的:请求一般会返回与T&完全相同但行为不像T的内容。事实上,这个返回的东西实际上不是引用,必须以某种方式让用户(和编译器!)知道。

答案 1 :(得分:1)

好吧,你可以用包装器来做。为你的重载列表创建一个包装器 - &gt;但从未为您提供访问真实参考的权限。我想可能有办法解决这种方法,但它必须是故意的。应该足够好,告知客户他们真的不应该这样做。

答案 2 :(得分:1)

您可以从此类继承,并创建一个匹配的构造函数来调用父类的构造函数(例如,具有相同的数据构造函数,只将数据传递给父类),并创建复制构造函数和复制任务私人。或者,您可以从boost :: noncopyable和该类派生。然后,您可以安全地使用指向基类的指针/引用。

编辑:如果该类有一个接口,你可以创建一个实现该接口的装饰器,它是不可复制的,并且不提供获取它所包装的对象的引用/指针的方法。

如果这些都不是一个选项,你可以编写一个具有相同方法的类,并且看起来相同,没有复制构造函数和复制赋值,这将调用你正在守护的类的相应方法(再次,装饰,艰难的方式)。但我会避免这种情况。

答案 3 :(得分:1)

我不相信语言中有任何东西可以让你这样做。可以说,你可以返回一个指针,这样他们就必须采取明确的行动来复制它。

OTOH,这是你可以使用的包装器的一个例子。请注意,Uncopyable按值返回,而不是引用。 (但这没关系,因为它可能只是指针大小。)

#include <iostream>
#include <list>

template <typename T>
class Uncopyable
{
public:
    Uncopyable(T& r) : ref(r) {}

    T* operator->() { return &ref; }

private:
    T& ref;
};

Uncopyable<std::list<int> > get_list()
{
    static std::list<int> l;
    l.push_back(l.size());
    return l;
}

int main() 
{
    for (int i = 0; i < 10; ++i)
    {
        Uncopyable<std::list<int> > my_l = get_list();
        std::cout << my_l->size() << std::endl;
    }
}

答案 4 :(得分:1)

我发现这是一个奇怪的请求。复制列表或使用它作为参考的策略应该由用户正常使用,但如果由于某种原因,复制列表永远不正确,那么包装类可以解决问题。

如果用户知道他在做什么,他应该理解使用列表的深层副本与使用浅层副本和修改原始副本之间的区别。如果用户不理解这一点,他就没有使用C ++的业务了。

[编辑]我刚注意到之前有人发布了几乎相同的解决方案。 课程可以很简单:

template <class T>
class NoncopyablePtr
{
private:
    T* ptr;

public:
    /*implicit*/ NoncopyablePtr(T* iptr): ptr(iptr) {}

    T* operator->() const
    {
        return ptr;
    }
};

这会让用户很难复制指针。他们必须打电话给操作员 - &gt;明确地取消引用结果。现在只需返回NoncopyablePtr&lt;的std ::列表&LT; int&gt; &GT;而且你会让客户(甚至不是不可能)对该列表进行复制。

如果您不喜欢使用operator-&gt;那么我担心没有其他方法可以阻止用户轻松复制结果。