4

如果我有一个函数返回对我无法控制其源的类实例的引用,请说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

4

5 回答 5

2

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

期望的行为是不可能的:请求能够一般地返回看起来完全像 aT&但行为不像 a 的东西T。这个返回的东西实际上不是引用的事实必须以某种方式让用户(和编译器!)知道。

于 2010-06-24T00:51:19.537 回答
1

我觉得这是一个奇怪的要求。复制列表或将其用作参考的策略通常应由用户决定,但如果由于某种原因,复制列表永远不正确,那么包装类就可以解决问题。

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

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

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

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

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

这将使用户很难复制指针。他们必须显式调用 operator-> 并取消引用结果。现在只需返回 NoncopyablePtr< std::list< int >> ,您就会让客户(尽管并非不可能)制作该列表的副本变得非常困难。

如果您不喜欢使用 operator-> ,那么恐怕真的没有其他方法可以阻止用户轻松复制结果。

于 2010-06-24T10:15:03.250 回答
1

好吧,你可以用一个包装器来做。为您的列表制作一个重载的包装器 -> 但永远不会为您提供对真实参考的访问。我想可能有办法解决这种方法,但它必须是故意的。应该足以告知客户他们真的不应该这样做。

于 2010-06-23T23:37:24.627 回答
1

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

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

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

于 2010-06-23T23:38:19.623 回答
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;
    }
}
于 2010-06-23T23:52:55.960 回答