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

C++ const_cast和std::move从非引用中删除constness,c++,c++11,constants,move-semantics,C++,C++11,Constants,Move Semantics,我有一个无法修改的外部库。库声明了一个模板函数,该函数出于某种原因返回const非引用对象: template<class C> const C foo(); 现在我需要使用foo。一个简单的用法: bar buz() { return foo<bar>(); } bar buz(){ 返回foo(); } 失败于 main.cpp:在函数“bar buz()”中: main.cpp:13:21:错误:使用已删除的函数'bar::bar(const bar&

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

template<class C>
const C foo();
现在我需要使用
foo
。一个简单的用法:

bar buz() {
    return foo<bar>();
}
bar buz(){
返回foo();
}
失败于

main.cpp:在函数“bar buz()”中:
main.cpp:13:21:错误:使用已删除的函数'bar::bar(const bar&)'
返回foo();
^
main.cpp:8:5:注:此处声明
条(常数条&)=删除;
^~~
这是有道理的,没有简单的解决方法可以使代码编译

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

bar buz() {
    return const_cast<bar&&>(std::move(foo<bar>()));
}
bar buz(){
返回常量cast(std::move(foo());
}
它进行编译,整个代码按预期工作(不仅是上面的简化示例,还有我的真实代码)

然而,这是安全的,还是我遇到了一些未定义的行为?有更好的解决办法吗



我已经阅读并理解了有关从函数(,)和“常见的答案”返回“<代码> const <代码> >的问题:在现代C++中,返回< <代码> const <代码>对象是令人沮丧的,但我的问题不是关于它的,但是关于如何解决外部库返回

const
对象的情况。

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


也就是说,它可能在您的环境中工作,我看不到更好的解决方法。

由于函数调用的结果根据定义是一个R值本身,您不需要在返回语句中对其应用
std::move
-
const_cast(foo())
就足够了。这使得代码更易于阅读

仍然-没有标准保证这将始终适用于所有
bar
类型。更重要的是,在某些情况下,这可能会导致未定义的行为。(想象一下一些非常侵入性的优化,它完全消除了
foo
,并使其结果成为“静态数据”中的对象)内存段-如
foo
constexpr
。然后调用移动构造函数(可能修改其参数),可能会导致访问冲突(异常)


您所能做的就是切换到不同的库(或者,如果可能的话,请库维护人员修复API),或者创建一些单元测试并将其包含在构建过程中-只要测试通过,您就应该可以(记住使用与“生产”中相同的优化设置)build-
const\u cast
是强烈依赖于编译设置的内容之一。

如果
bar
的移动构造函数修改了任何内容,丢弃const将导致未定义的行为。您可能可以这样解决您的问题,而不引入未定义的行为:

struct wrapped_bar {
    mutable bar wrapped;
};

bar buz()
{
    return foo<wrapped_bar>().wrapped;
}
struct-wrapped\u条{
可变棒包装;
};
巴布兹()
{
返回foo().wrapped;
}

使
wrapped
成员可变意味着该成员是非常量的,即使
wrapped\u bar
对象作为一个整体是常量。根据
foo()
的工作方式,您可能需要向
wrapped_bar
添加成员,使其更像
bar

问题中的隐含假设是API在这里是错误的。你正在使用的图书馆是什么?您要解决的问题是什么,需要您处理API?
const\u cast(foo())
还不够吗?它仍然在return语句中留下未命名的对象,所以move语义应该起作用in@Petr:/sad,我会尝试
const\u cast
而不使用
std::move
,只是为了让它更简单。另外-您确定foo中没有任何特定的东西使
const
合理吗?不要依赖于未定义的行为。如果需要,请切换库needed@Petr嗯,我更喜欢保证能工作的长代码,而不是将来可能中断的短代码:)@DavidHaim,首先,它被创建为
const
。返回的临时对象是一个单独的对象,函数签名要求它是常量。然后,可能是基于OP自己的语句(整个代码工作正常)。纯粹的推测。说“可能是未定义的行为”是这里唯一确定的答案,因为OP只关心。@sleeptightpupper,你能详细说明我在这里猜测的是哪一点吗?我不认为是常量施法导致了UB,事实上,如果你修改声明为常量的实际对象。@0x499602D2,这确实是真的-然而,我是用代码来回答这个特定的问题的,代码中有这样的用法(最有可能的是,rvalue-ctor做了一些修改)。为了清晰起见,我仍将进行编辑。+1好主意!鉴于
wrapped_bar
buz()
的一个实现细节,最好在
buz()
的主体中定义它。当然,所有这些都依赖于
foo
为任何
T
工作。
bar buz() {
    return const_cast<bar&&>(std::move(foo<bar>()));
}
struct wrapped_bar {
    mutable bar wrapped;
};

bar buz()
{
    return foo<wrapped_bar>().wrapped;
}