我们可以从函数中按值返回具有已删除/私有复制/移动构造函数的对象吗?
在 C++03 中,不可能按值返回具有私有非定义复制构造函数的类的对象:
struct A { A(int x) { ... } private: A(A const&); };
A f() {
return A(10); // error!
return 10; // error too!
}
我想知道,C++11 中是否取消了此限制,使得可以编写具有类类型的函数没有用于复制或移动的构造函数的类的返回类型?我记得允许函数的调用者使用新返回的对象可能很有用,但他们无法复制该值并将其存储在某个地方。
In C++03 it is impossible to return an object of a class having a private non-defined copy constructor by value:
struct A { A(int x) { ... } private: A(A const&); };
A f() {
return A(10); // error!
return 10; // error too!
}
I was wondering, was this restriction lifted in C++11, making it possible to write functions having a class type return type for classes without constructors used for copy or move? I remember it could be useful to allow callers of a function use the newly returned object, but that they are not able to copy the value and store it somewhere.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是它的工作原理
即使
A
没有工作副本或移动构造函数,也没有其他可以复制或移动A
的构造函数,它仍然有效!为了利用 C++11 的这一功能,构造函数(在本例中采用
int
)必须是非显式的。Here is how it can work
This works even though
A
has no working copy or move constructor and no other constructor that could copy or move anA
!To make use of this feature of C++11, the constructor (taking
int
in this case) has to be non-explicit though.该限制尚未解除。根据访问说明符,§12.8/32 中有一条注释解释:
从删除的复制/移动构造函数开始,§8.4.3/2 指出
不确定这种特殊情况,但我对引用的理解是,如果在 §12.8/32 中的重载决策之后选择了删除的复制/移动构造函数,即使操作被省略,也可能构成引用该函数,并且程序的格式将不正确。
The restriction has not been lifted. As per the access specifier, there is a note in §12.8/32 that explains:
As of the deleted copy/move constructors §8.4.3/2 states that
Not sure about this particular case, but my understanding of the quote is that, if after the overload resolution in §12.8/32 the deleted copy/move constructor is selected, even if the operation is elided, that could constitute a reference to the function, and the program would be ill formed.
上面的代码在 C++11 中仍然是格式错误的。但是你可以向
A
添加一个公共移动构造函数,这样它就合法了:The above code is still ill-formed in C++11. But you could add a public move constructor to
A
and then it would be legal:怎么可能呢?通过按值返回某些内容,根据定义,您正在复制(或移动)它。虽然 C++ 可以允许在某些情况下省略复制/移动,但它仍然按照规范进行复制(或移动)。
是的。您摆脱了复制构造函数/赋值,但允许移动值。
std::unique_ptr
就是这样做的。您可以按值返回
unique_ptr
。但这样做时,您将返回一个“纯右值”:一个正在被销毁的临时值。因此,如果你有一个这样的函数g
:你可以这样做:
但不是this:
但是这个是可能:
第二行调用
value
上的移动赋值运算符。它将删除旧指针并将新指针移入其中,将旧值保留为空。通过这种方式,您可以确保任何
unique_ptr
的内容仅存储在一个位置。您无法阻止它们在多个位置引用它(通过指向unique_ptr
的指针或其他方式),但内存中最多只有一个位置存储实际指针。删除复制和移动构造函数会创建一个不可移动对象。它被创建的地方就是它的价值所在的地方,永远。移动让您拥有独特的所有权,但又不至于一动不动。
How could it be? By returning something by value, you are by definition copying (or moving) it. And while C++ can allow that copy/move to be elided in certain circumstances, it's still copying (or moving) by the specification.
Yes. You get rid of the copy constructor/assignment, but allow the value to be moved.
std::unique_ptr
does this.You can return a
unique_ptr
by value. But in doing so, you are returning an "prvalue": a temporary that is being destroyed. Therefore, if you have a functiong
as such:You can do this:
But not this:
But this is possible:
The second line invokes the move assignment operator on
value
. It will delete the old pointer and move the new pointer into it, leaving the old value empty.In this way, you can ensure that the contents of any
unique_ptr
is only ever stored in one place. You can't stop them from referencing it in multiple places (via pointers tounique_ptr
or whatever), but there will be at most one location in memory where the actual pointer is stored.Removing both the copy and move constructors creates an immobile object. Where it is created is where it's values stay, forever. Movement allows you to have unique ownership, but without being immobile.
如果您确实想要的话,您可能可以将代理组合在一起来实现这一目的,并有一个转换构造函数来复制代理中存储的值。
不过,
您可能可以在 03 中使用
auto_ptr
执行相同的操作。显然,它不会阻止存储结果对象
,尽管它确实限制每个实例只能保存一份副本。You could probably hack together a proxy to do the trick if you really wanted, and have a converting constructor that copies the value stored within the proxy.
Something along the lines of:
You could probably do the same in 03, though, using
auto_ptr
s. And it obviously doesn't prevent storage of the resultantObject
, although it does limit you to one copy per instance.