C++ 返回值的初始化应忽略自动对象的常量
为了保持常量的正确性,您可能希望将C++ 返回值的初始化应忽略自动对象的常量,c++,c++11,return,move-semantics,const-correctness,C++,C++11,Return,Move Semantics,Const Correctness,为了保持常量的正确性,您可能希望将类型的本地对象设置为唯一的\u ptr常量,如下所示,而T在这里是一些不重要的类型: unique_ptr<T> foo() { const unique_ptr<T> p = make_unique<T>(...); ... using p's pointee ... return p; } unique_ptr foo(){ const unique_ptr p=make_unique(…); …
类型的本地对象设置为唯一的\u ptr
常量,如下所示,而T
在这里是一些不重要的类型:
unique_ptr<T> foo() {
const unique_ptr<T> p = make_unique<T>(...);
... using p's pointee ...
return p;
}
unique_ptr foo(){
const unique_ptr p=make_unique(…);
…使用p的指针。。。
返回p;
}
不幸的是,它无法编译,因为返回值无法初始化,因为unique\u ptr
没有复制构造函数,而移动构造函数不可行,因为p
是常量
如果C++标准会说,当返回语句的“操作数”是一个自动对象时,它的潜在稳定性会被忽略吗?自动对象在返回值初始化后不能被引用,因此它的常量现在不相关。在它的析构函数中,const对象也可以被修改,所以它实际上只是定义constness结束的位置:在析构函数之前,或者在这个特殊情况下在返回值的构造函数之前
然而,“不能被引用”并不是全部事实:初始化返回值后排序的其他局部变量的析构函数可能引用它。但是我认为他们不可能关心const对象被修改了。他们通过指向常量的指针或引用来了解对象,也就是说,从他们的角度来看,他们只知道不允许修改它,他们不知道是否允许其他人修改它
你认为对C++标准的这种改变会是个好主意吗?或者,除了我在下面给出的解决方案之外,您还看到了其他解决方案吗
仅供记录:非解决方案和其他解决方案:
- 您不能
因为现在您有两个返回unique_ptr(p.get())
s,每个人都认为它是唯一的所有者unique_ptr
- 您不能
,因为返回unique_ptr(p.release())
是常量,而p
是非常量成员方法release()
没有任何用处,因为它不会删除常量,因此仍然无法调用移动构造函数返回移动(p)
- 编辑:正如Chris Beck指出的那样,
也不是解决方案,因为修改const对象是未定义的行为(标准N4140中的7.1.6.1 p4)return const_cast(p)
- 我认为这样的改变是个坏主意。我有点明白你是从哪里来的,但是你对你的问题的解决方案只会产生一个目前已经解决的新问题
我想我们首先要考虑为什么我们要创建对象<代码> const >
这是关于安全和确保给定变量不会发生错误的事情。通过创建一个唯一的\u ptr
常量
,实际上就是说您不希望在对象上发生任何所有权操纵。您仍然可以操作它管理的对象:
std::unique_ptr<T> foo()
{
// const object means no calling non-const member functions
// which means no changing the ownership of the managed pointer
const std::unique_ptr<int> p = std::make_unique<int>();
// but we still get to manipulate the thing being pointed to:
*p = 6;
return std::move(p); // compile error - changing ownership
}
std::unique_ptr foo()
{
//常量对象表示不调用非常量成员函数
//这意味着不更改托管指针的所有权
const std::unique_ptr p=std::make_unique();
//但我们仍然可以操纵被指向的东西:
*p=6;
返回std::move(p);//编译错误-更改所有权
}
在这种情况下,您可能希望使您的唯一\u ptr
常量
避免意外返回它,而不是确实想要返回的另一个唯一\u ptr
。使唯一\u ptr
常量实际上可以防止它被错误返回。因此,我们现在可以做的是使所有的对象都是唯一的\u ptr
对象const
,除了我们希望将其所有权返回给调用方的对象之外
您的更改将使该保护无效,并且在开始时使对象
常量没有什么意义。由于unique\u ptr是一种仅移动的类型,按值返回将(假设)调用返回值的移动构造函数。
但由于从中移动是一种破坏性的操作,所以不能真正从常量对象中移动
但我认为C++17的“保证的副本省略”(assured copy elision)会对此有所帮助。
基本上,这将允许不可移动的类型通过函数的值返回,例如const unique_ptr。
再一次,我担心,您将不得不等待新标准的出台当然,另一个解决方案是首先不要将其设置为常量?但从我目前的观点来看,我不得不放弃常量正确性,没有充分的理由。如果您想通过释放对象作为返回值来修改对象,那么将其设置为常量是不正确的。您能否更详细地解释一下const unique\u ptr
的好处是什么?@M.M与标记任何局部变量const的好处相同。有些人认为const应该是默认值(如在SML中)。我同意我真正想要的是能够表示名为p
的本地对象是返回值-应该只有一个对象,而不是两个。也就是说,我不想被迫使用我需要的模型来初始化另一个对象的返回值,这里是p
。当前标准中的复制省略没有帮助,因为即使使用它,概念上仍然有两个对象,而不是一个。考虑到资源管理类,使用const,我确实想表示在对象的生命周期内(即直到析构函数调用)不应修改所有权。