有什么方法可以正确 std::move const 数据吗?
Is there any way to correctly std::move const data?
我的问题是我必须在复制 const 数据和移动非 const 数据之间做出选择,而且我在概念上看不出为什么在我的情况下将 const 数据移动到一个常量目的地。我也知道从 const 对象移动是不合逻辑的 - 所以也许有其他方法可以实现我正在尝试做的事情...
我有一个生成器 class,它设置了一个我不想复制的 BigData 对象。一旦构建器完成,它将 'emits' 数据作为常量,因为在那之后不应修改它。构建器是临时的,然后可以丢弃,但数据应该继续存在,作为包装器 class 中的 const 成员可以查询它。构建器是一个通用类型(不知道数据的细节),而包装器是特定于数据内容的。这是通过数据中的类型擦除实现的,但这与这个问题无关,只是要明确表示不希望合并构建器和包装器。
下面的代码描述了上面的内容,除非您删除 BigData 的移动构造函数,否则不会编译。编译错误表明这段代码会复制数据,这是不可取的:
prog.cpp:26:57: error: use of deleted function ‘constexpr BigData::BigData(const BigData&)’
Wrapper( const BigData&& In ) : Data( std::move(In) ) {}
^
class BigData
{
// Only a builder can create data
friend class Builder;
BigData() = default;
public:
// Move only
BigData( BigData&& ) = default;
};
class Builder
{
BigData Data;
public:
const BigData&& Build() & { return std::move(Data); }
// Functions to set up data go here
};
class Wrapper
{
const BigData Data;
public:
Wrapper( const BigData&& In ) : Data( std::move(In) ) {}
// Functions to query data go here
};
std::unique_ptr<Wrapper> DoBuild()
{
Builder b;
// call functions on b to set up data here
return std::make_unique<Wrapper>( b.Build() );
}
以上代码也可以在https://ideone.com/tFkVEd.
找到
问题可以通过将所有 const BigData&&
更改为仅 BigData&&
来解决,但我不希望数据在从 Build()
检索到后可以更改。
最后,这个问题也可以通过在 unique_ptr<const BigData>
中从 Build 返回数据来解决,并让 Wrapper 拥有它的所有权,但我的问题是指针可以为空,所以在 Wrapper 中使用 Data 必须首先检查 Data 指针是否有效。这就是为什么我想通过右值引用将 const 数据移动到包装器中,也是为什么必须用数据构造包装器的原因。
有没有办法实现我想要的,或者我是否遇到了 c++ 的限制?
非常感谢您的投入。
注意:我在尝试自己解决这个问题时遇到的相关问题:
- Return value or rvalue reference?
- Is returning by rvalue reference more efficient?
无法 std::move
a const T
因为它会改变给定的对象。 (除非你让成员 mutable
并让 T(const T&&)
构造函数来做移动,我不推荐这样做)。
我认为更好的解决方案是将所有变异函数设为私有,这样只有构建者才能访问它们,并且 return T&&
.
首先,移动一个对象,确切的意思是修改它。
其次,我认为您不应该阻止对 BigData
的所有修改。试图 return 一个 BigData const&&
并阻止它被修改,就像试图阻止它被 const_cast
编辑一样,这是一种浪费。在这种情况下,您可以声明 在 Builder
中修改 BigData
绝对是 未定义的行为 ,除了移动它 然后 return 一个 BigData&&
.
第三,如果你希望它不被完全修改(移动除外),你应该考虑是否构造一个Wrapper
是唯一的用法Builder
。如果是这样,为什么不提供构造函数 Wrapper(Build&)
来做到这一点?它可以防止从 Builder
到 Wrapper
.
的所有潜在修改
最后,为了回答如何移动一个const BigData
对象这个问题,我建议BigData(BigData const&&)
和const_cast
,这意味着你允许所有 const BigData
都将被移动,就好像它是非常量一样。
我的问题是我必须在复制 const 数据和移动非 const 数据之间做出选择,而且我在概念上看不出为什么在我的情况下将 const 数据移动到一个常量目的地。我也知道从 const 对象移动是不合逻辑的 - 所以也许有其他方法可以实现我正在尝试做的事情...
我有一个生成器 class,它设置了一个我不想复制的 BigData 对象。一旦构建器完成,它将 'emits' 数据作为常量,因为在那之后不应修改它。构建器是临时的,然后可以丢弃,但数据应该继续存在,作为包装器 class 中的 const 成员可以查询它。构建器是一个通用类型(不知道数据的细节),而包装器是特定于数据内容的。这是通过数据中的类型擦除实现的,但这与这个问题无关,只是要明确表示不希望合并构建器和包装器。
下面的代码描述了上面的内容,除非您删除 BigData 的移动构造函数,否则不会编译。编译错误表明这段代码会复制数据,这是不可取的:
prog.cpp:26:57: error: use of deleted function ‘constexpr BigData::BigData(const BigData&)’ Wrapper( const BigData&& In ) : Data( std::move(In) ) {} ^
class BigData
{
// Only a builder can create data
friend class Builder;
BigData() = default;
public:
// Move only
BigData( BigData&& ) = default;
};
class Builder
{
BigData Data;
public:
const BigData&& Build() & { return std::move(Data); }
// Functions to set up data go here
};
class Wrapper
{
const BigData Data;
public:
Wrapper( const BigData&& In ) : Data( std::move(In) ) {}
// Functions to query data go here
};
std::unique_ptr<Wrapper> DoBuild()
{
Builder b;
// call functions on b to set up data here
return std::make_unique<Wrapper>( b.Build() );
}
以上代码也可以在https://ideone.com/tFkVEd.
找到问题可以通过将所有 const BigData&&
更改为仅 BigData&&
来解决,但我不希望数据在从 Build()
检索到后可以更改。
最后,这个问题也可以通过在 unique_ptr<const BigData>
中从 Build 返回数据来解决,并让 Wrapper 拥有它的所有权,但我的问题是指针可以为空,所以在 Wrapper 中使用 Data 必须首先检查 Data 指针是否有效。这就是为什么我想通过右值引用将 const 数据移动到包装器中,也是为什么必须用数据构造包装器的原因。
有没有办法实现我想要的,或者我是否遇到了 c++ 的限制?
非常感谢您的投入。
注意:我在尝试自己解决这个问题时遇到的相关问题:
- Return value or rvalue reference?
- Is returning by rvalue reference more efficient?
无法 std::move
a const T
因为它会改变给定的对象。 (除非你让成员 mutable
并让 T(const T&&)
构造函数来做移动,我不推荐这样做)。
我认为更好的解决方案是将所有变异函数设为私有,这样只有构建者才能访问它们,并且 return T&&
.
首先,移动一个对象,确切的意思是修改它。
其次,我认为您不应该阻止对 BigData
的所有修改。试图 return 一个 BigData const&&
并阻止它被修改,就像试图阻止它被 const_cast
编辑一样,这是一种浪费。在这种情况下,您可以声明 在 Builder
中修改 BigData
绝对是 未定义的行为 ,除了移动它 然后 return 一个 BigData&&
.
第三,如果你希望它不被完全修改(移动除外),你应该考虑是否构造一个Wrapper
是唯一的用法Builder
。如果是这样,为什么不提供构造函数 Wrapper(Build&)
来做到这一点?它可以防止从 Builder
到 Wrapper
.
最后,为了回答如何移动一个const BigData
对象这个问题,我建议BigData(BigData const&&)
和const_cast
,这意味着你允许所有 const BigData
都将被移动,就好像它是非常量一样。