繁体   English   中英

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

[英]Preventing copy construction and assignment of a return value reference

如果我有一个函数返回对我无法控制其源的类实例的引用,请说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执行此操作,我不能简单地将copy-constructor和赋值运算符设为private

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

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

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

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

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

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

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

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;
    }
}

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

如果用户知道他在做什么,他应该理解使用列表的深层副本与使用浅层副本和修改原始副本之间的区别。 如果用户不理解这一点,他还没有使用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->那么我担心没有其他方法可以阻止用户轻松复制结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM