当你有一个带有移动构造函数的派生对象,并且基础对象也有移动语义时,从派生对象移动构造函数调用基础对象移动构造函数的正确方法是什么?
我首先尝试了最明显的事情:
Derived(Derived&& rval) : Base(rval)
{ }
Run Code Online (Sandbox Code Playgroud)
但是,这似乎最终调用了Base对象的复制构造函数.然后我尝试std::move在这里明确使用,像这样:
Derived(Derived&& rval) : Base(std::move(rval))
{ }
Run Code Online (Sandbox Code Playgroud)
这有效,但我很困惑为什么这是必要的.我以为std::move只返回一个右值引用.但是因为在这个例子rval中已经是一个右值引用,所以调用std::move应该是多余的.但如果我不在std::move这里使用,它只是调用复制构造函数.那么为什么要求std::move必要?
在底部更新
问题1:如何为管理相当繁重的资源的类实现五条规则,但是您希望它按值传递,因为这极大地简化并美化了它的用法?或者甚至不需要所有五项规则?
在实践中,我开始使用3D成像,其中图像通常是128*128*128双倍.能够写这样的东西会让数学变得更容易:
Data a = MakeData();
Data c = 5 * a + ( 1 + MakeMoreData() ) / 3;
Run Code Online (Sandbox Code Playgroud)
问题2:使用复制省略/ RVO /移动语义的组合,编译器应该能够以最少的复制完成此操作,不是吗?
我试图找出如何做到这一点,所以我从基础开始; 假设一个对象实现了实现复制和赋值的传统方式:
class AnObject
{
public:
AnObject( size_t n = 0 ) :
n( n ),
a( new int[ n ] )
{}
AnObject( const AnObject& rh ) :
n( rh.n ),
a( new int[ rh.n ] )
{
std::copy( rh.a, rh.a + n, a );
}
AnObject& operator = ( …Run Code Online (Sandbox Code Playgroud) 在实现移动构造函数和移动赋值运算符时,通常会编写如下代码:
p = other.p;
other.p = 0;
Run Code Online (Sandbox Code Playgroud)
隐式定义的移动操作将使用以下代码实现:
p = std::move(other.p);
Run Code Online (Sandbox Code Playgroud)
这将是错误的,因为移动指针变量并没有将其设置为null.这是为什么?是否有任何情况我们希望移动操作保持原始指针变量不变?
注意:通过"移动",我不只是表示子表达式std::move(other.p),我的意思是整个表达式p = std::move(other.p).那么,为什么没有特殊的语言规则说"如果赋值的右侧是指针xvalue,则在赋值发生后将其设置为null."?
C++ 11标准对标准库相关的自移动赋值有何看法?更具体的是,什么(如果有的话)保证什么selfAssign呢?
template<class T>
std::vector<T> selfAssign(std::vector<T> v) {
v = std::move(v);
return v;
}
Run Code Online (Sandbox Code Playgroud) 我正在回答一个问题并建议为大型类型返回按值,因为我相信编译器会执行返回值优化(RVO).但后来有人向我指出Visual Studio 2013没有在我的代码上执行RVO.
我在这里发现了一个关于Visual Studio无法执行RVO的问题,但在这种情况下,结论似乎是,如果真的很重要Visual Studio将执行RVO.在我的情况下它确实很重要,它对性能产生了重大影响,我已经通过分析结果证实了这一点.这是简化的代码:
#include <vector>
#include <numeric>
#include <iostream>
struct Foo {
std::vector<double> v;
Foo(std::vector<double> _v) : v(std::move(_v)) {}
};
Foo getBigFoo() {
std::vector<double> v(1000000);
std::iota(v.begin(), v.end(), 0); // Fill vector with non-trivial data
return Foo(std::move(v)); // Expecting RVO to happen here.
}
int main() {
std::cout << "Press any key to start test...";
std::cin.ignore();
for (int i = 0; i != 100; ++i) { …Run Code Online (Sandbox Code Playgroud) 因此,在查找移动语义之后,我发现当您打算转移所有权时,普遍的共识是通过值传递.但在Scott Meyer关于Universal引用的讨论中,我注意到std::vector::push_back有2个重载:
void push_back( const T& value );
void push_back( T&& value );
Run Code Online (Sandbox Code Playgroud)
所以我心想,void push_back( T value );不够吗?我问了一些最终导致以下测试用例的人:
#include <memory>
#include <iostream>
#include <type_traits>
struct A
{
A() { std::cout << "A Default constructor\n"; }
A(const A &) { std::cout << "A Copy\n"; }
A(A &&) { std::cout << "A Move\n"; }
};
std::aligned_storage<sizeof(A)> contents;
A& alias = *reinterpret_cast<A*>(&contents);
void ByVal(A a)
{
new (&contents) A(std::move(a));
alias.~A();
}
void ByLCRef(A const& a)
{
new …Run Code Online (Sandbox Code Playgroud) 该锈语言网站索赔移动语义的语言的特征之一.但我无法看到Rust中如何实现移动语义.
Rust box是唯一使用移动语义的地方.
let x = Box::new(5);
let y: Box<i32> = x; // x is 'moved'
Run Code Online (Sandbox Code Playgroud)
上面的Rust代码可以用C++编写
auto x = std::make_unique<int>();
auto y = std::move(x); // Note the explicit move
Run Code Online (Sandbox Code Playgroud)
据我所知(如果我错了,请纠正我),
Rust如何提供移动语义?
我知道通常标准对已经移动的值的要求很少:
N3485 17.6.5.15 [lib.types.movedfrom]/1:
可以从(12.8)移动C++标准库中定义的类型的对象.可以显式指定或隐式生成移动操作.除非另有规定,否则此类移动物体应置于有效但未指定的状态.
我找不到任何与vector此明确排除的内容.但是,我无法想出一个理智的实现,导致向量不为空.
是否有一些标准需要我缺少或者类似于在C++ 03中作为连续缓冲区处理basic_string?
可能重复:
移动语义==自定义交换功能已过时?
这就是std::swapC++ 11中的样子:
template<typename T>
void swap(T& x, T& y)
{
T z = std::move(x);
x = std::move(y);
y = std::move(z);
}
Run Code Online (Sandbox Code Playgroud)
如果我的类定义了移动构造函数和移动赋值运算符,我还是必须专注std::swap于我自己的类型,或者它会std::swap尽可能高效吗?
std :: array是否可以移动?
在Bjarne Native 2012演示幻灯片(幻灯片41)中,它std::array列为唯一不可移动的容器之一.
快速浏览gcc 4.8库源代码似乎证实std::array不可移动:
的std ::向量:
/* @brief %Vector move constructor.
... */
vector(vector&& __x) noexcept
: _Base(std::move(__x)) { }
Run Code Online (Sandbox Code Playgroud)
在std :: array中,接收rvalue引用参数的唯一方法是随机元素访问,这避免了通过复制返回:
get(array<_Tp, _Nm>&& __arr) noexcept
{ /*...*/ return std::move(get<_Int>(__arr)); }
Run Code Online (Sandbox Code Playgroud)
是否std::array创建了默认的move-constructor和move-assignment ,或者是std::array不可移动的?如果它是不可移动的,为什么std::array不能移动std::vector呢?