const_cast和std :: move从非引用中删除constness

Pet*_*etr 20 c++ const move-semantics c++11

我有一个外部库,我无法修改.该库声明了一个模板函数,该函数由于某种原因返回const非引用对象:

template<class C>
const C foo();
Run Code Online (Sandbox Code Playgroud)

我有另一个外部库,我无法修改.该库声明了一个不可复制的类,并且只有非const对象的移动构造函数:

struct bar {
    bar();
    bar(const bar&)=delete;
    bar(bar&&);
};
Run Code Online (Sandbox Code Playgroud)

现在我需要使用foo<bar>.一个简单的用法:

bar buz() {
    return foo<bar>();
}
Run Code Online (Sandbox Code Playgroud)

失败了

main.cpp: In function 'bar buz()':
main.cpp:13:21: error: use of deleted function 'bar::bar(const bar&)'
     return foo<bar>();
                     ^
main.cpp:8:5: note: declared here
     bar(const bar&)=delete;
     ^~~
Run Code Online (Sandbox Code Playgroud)

这是有道理的,并没有简单的解决方法使代码编译.

但是,如果我添加一些更复杂的解决方法:

bar buz() {
    return const_cast<bar&&>(std::move(foo<bar>()));
}
Run Code Online (Sandbox Code Playgroud)

它编译并且整个代码按预期工作(不仅是上面的简化示例,而且我的真实代码也是如此).

但是,它是安全的,还是我遇到了一些未定义的行为?有没有更好的解决方法?


我已阅读并理解有关返回的问题const从功能(1,2),以及常见的答案似乎是返回const对象在现代C++气馁,但我的问题是不是这件事,但我如何能解决该情况当外部库返回const对象时.

Vau*_*ato 7

如果移动构造函数用于bar修改任何内容,则转换const将导致未定义的行为.你可以解决这个问题,而不会引入未定义的行为:

struct wrapped_bar {
    mutable bar wrapped;
};

bar buz()
{
    return foo<wrapped_bar>().wrapped;
}
Run Code Online (Sandbox Code Playgroud)

使wrapped成员变为可变意味着该成员是非const的,即使该wrapped_bar对象作为整体是const.根据foo()工作原理,您可能需要添加成员wrapped_bar以使其更像是一个工作bar.


Ser*_*eyA 5

从技术上讲,您正在将程序暴露给未定义的行为。由于声明了原始对象C(临时对象)const,因此对其进行常量转换和修改是非法的并且违反标准。(我假设,移动构造函数对移动对象进行了一些修改)。

话虽这么说,它可能适用于您的环境,但我没有看到更好的解决方法。

  • @DavidHaim,首先,它被创建为“const”。返回的临时对象是一个单独的对象,函数签名要求它是 const。然后,*可能*是基于OP自己的声明(*并且整个代码按预期工作*)。 (2认同)