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

发布于 2024-09-06 23:19:10 字数 870 浏览 2 评论 0原文

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

list<int>& f();

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

list<int> &a_list = f();

如果用户要执行以下操作:

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

我希望它是一个编译时错误,因为用户将仅操作列表的副本而不是原始列表(即从来不是我的应用程序的预期/想要的)。

有什么方法可以防止上面的复制构造和赋值(例如通过某种“包装器”类)?

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


是的,我知道对于我确实可以控制的类,我可以简单地将复制构造函数和赋值运算符设为私有,例如:

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

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

If I have a function that returns a reference to an instance of a class that I don't have control over its source, say list<int>:

list<int>& f();

I want to ensure that its value is only assigned to another reference, e.g.:

list<int> &a_list = f();

If the user were instead to do:

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

I want it to be a compile-time error since the user would be manipulating only a copy of the list and not the original list (which is never what is intended/wanted for my application).

Is there any way to prevent copy-construction and assignment in the above (say via some kind of "wrapper" class)?

Ideally, if some wrapper class were to be used, say wrapper<T>, I'd like it to work for objects of any type T.


Yes, I know that for a class that I do have control over, I can simply make the copy-constructor and assignment operator private like:

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

to forbid copy-construction and assignment; but, as shown above, I want to do this for, say, std::list for which I can not simply make the copy-constructor and assignment operator private.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

岁月苍老的讽刺 2024-09-13 23:19:10

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

所需的行为是不可能的:请求通常能够返回看起来与 T& 完全相同的内容,但其行为却不像 T.事实上,这个返回的东西实际上并不是一个引用,必须以某种方式让用户(和编译器!)知道。

This is a separate answer from my previous one, since the problem has been clarified. My previous answer might be useful to someone with sane requirements, so I leave it intact.

The desired behavior is impossible: the request is to be able to generically return something that looks exactly like a T& but that does not behave like a T. The fact that this returned thing is NOT actually a reference must be made known the the user (and compiler!) in some way.

鸠书 2024-09-13 23:19:10

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

Well, you could do it with a wrapper. Make a wrapper for your list that overloads -> but never provides you with access to the real reference. I imagine there are probably ways to work around such a method but it would have to be on purpose. Should be good enough to inform the client they really shouldn't be doing it.

长发绾君心 2024-09-13 23:19:10

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

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

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

You can inherit from this class, and create a matching constructor to call the constructor of the parent class (for example, have the same data constructors, that just pass the data to the parent class), and make the copy constructor and copy assignment private. Or, you could derive from both boost::noncopyable and that class. You can then use a pointer/reference to the base class safely.

EDIT : If that class has an interface, you can make a decorator that implements that interface, that is not copyable, and doesn't provide a way to get a reference/pointer to the object it's wrapping.

If neither of these are an option, you could write a class that has the same exact methods, and looks the same, without a copy constructor and copy assignment, that would call the appropriate methods of the class you're guarding (again, decorator, the hard way). But I'd avoid that.

百善笑为先 2024-09-13 23:19:10

我不相信语言中有任何东西可以让你做到这一点。可以说,您可以返回一个指针,以便他们必须采取显式操作来复制它。

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

I don't believe there's anything in the language that lets you do this. Arguably, you could return a pointer so that they have to take explicit action to copy it.

OTOH, here's an example of a wrapper you could use. Note that Uncopyable gets returned by value, not reference. (But that's okay, since it's probably just pointer-sized.)

#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;
    }
}
月牙弯弯 2024-09-13 23:19:10

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

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

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

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

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

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

这将使用户很难复制被指者。他们必须致电接线员->明确并取消引用结果。现在只需返回 NoncopyablePtr< std::列表<整数> >而且你会让客户很难复制该列表(尽管并非不可能)。

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

I find this to be a bizarre request. The policy to copy the list or work with it as a reference should be up to the user normally, but if, for some reason, it is never correct to copy the list, then a wrapper class does the trick.

If the user knows what he's doing, he should understand the differences between working with a deep copy of the list as opposed to working with a shallow copy and modifying the original. If the user doesn't understand this, he has no business using C++ yet.

[Edit] I just noticed that someone posted an almost identical solution before.
The class can be quite simple:

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

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

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

This would make it very tough for the user to copy the pointee. They'd have to call operator-> explicitly and dereference the result. Now simply return NoncopyablePtr< std::list< int > > and you'll make it awfully tough on clients (though not impossible) to make a copy of that list.

If you don't like using operator-> then I'm afraid there's really no other way to prevent users from being able to easily copy the result.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文