C++ 移动语义:如何最好地理解/使用它们

C++ 移动语义:如何最好地理解/使用它们,c++,c++11,move-semantics,C++,C++11,Move Semantics,我在C++11的移动语义方面遇到问题。我正在使用带有-std=c++11开关的gcc 4.9.2 20150304(预发布),但我在移动构造函数未被调用方面遇到问题 我有以下源文件: densematrix.h \ifndef DENSEMATRIX\u H_ #定义密度矩阵_ #包括 #包括 #包括 类密度矩阵{ 私人: 尺寸m=0,n=0; 双*值=空PTR; 公众: /*执行器*/ 密度矩阵(大小t,大小t); /*复印机*/ DenseMatrix(const DenseMatrix

我在C++11的移动语义方面遇到问题。我正在使用带有-std=c++11开关的gcc 4.9.2 20150304(预发布),但我在移动构造函数未被调用方面遇到问题

我有以下源文件:

  • densematrix.h
\ifndef DENSEMATRIX\u H_
#定义密度矩阵_
#包括
#包括
#包括
类密度矩阵{
私人:
尺寸m=0,n=0;
双*值=空PTR;
公众:
/*执行器*/
密度矩阵(大小t,大小t);
/*复印机*/
DenseMatrix(const DenseMatrix&rhs);
/*移动驱动器*/
DenseMatrix(DenseMatrix&&rhs)无例外;
/*复印作业*/
const DenseMatrix&operator=(const DenseMatrix&rhs);
/*移动分配*/
const DenseMatrix&operator=(DenseMatrix&&rhs)noexcept;
/*矩阵乘法*/
DenseMatrix运算符*(常量DenseMatrix&rhs)常量;
/*dtor*/
~DenseMatrix();
};
#恩迪夫
  • densematrix.cpp
#包括“densematrix.h”
/*执行器*/
DensMatrix::DensMatrix(大小\u t m,大小\u t n):
m(m),n(n){

std::cout使用
运算符*
时的两个移动操作是因为您要求编译器不要执行复制/移动省略。这迫使编译器在
运算符*
(2参数构造函数调用)内部构造一个临时,然后将此临时移动到返回值中(移动构造函数调用)最后将返回值移动到目标对象(在您的示例中,移动构造函数/移动赋值调用)

通过打印print语句中涉及的对象的地址,我使您的示例变得更加嘈杂

std::cout << "move ctor called. " << this << std::endl;
最后,您可能希望将
double*
更改为
std::vector
,并避免所有
new
delete
调用。唯一需要注意的是,每当
vector::resize
时,
vector
值将初始化它添加的新元素,但这也是如此


更新以解决上次编辑中添加的代码

不仅不再需要析构函数定义,而且您也不需要任何复制/移动构造函数/赋值运算符。编译器将隐式地为您声明这些构造函数,它们与您的手写版本完全相同。因此,您在类中只需要构造函数定义和
o的构造函数定义Operator*
。这就是不手动管理内存的真正好处

我会对构造函数的定义做一些修改

    DenseMatrix( size_t m, size_t n,
        std::vector< double > values = {} ) : // <-- use list initialization, 
                                              //     no need to repeat type name
        m_( m ),
        n_( n ),
        values_( std::move(values) )          // <-- move the vector instead of copying
    {
        // ...
    }
DenseMatrix(尺寸m,尺寸n,

标准::向量值={})://哇!感谢您花时间结合现场演示给我如此详细的解释。同时,感谢您向我展示在调试消息中使用地址的诀窍。您能详细介绍一下在初始值设定项列表中使用
std::move
吗?在什么情况下这会有区别?我为什么要麻烦呢被
vector::resize
s行为所影响?这是因为我很可能会在乘法中覆盖初始化值,因此,我将毫无代价地承担元素初始化的开销吗?@ArdaAytekin
std::move
会在数据成员是从移动中受益的类型的情况下产生不同例如,如果将
values
设置为
std::vector
,则当前实现会在
values(std::move(rhs.values))时复制
rhs.values
将移动并构造它。您已经正确理解了
vector::resize
的缺点,在大多数情况下这不是什么大问题,但确实会增加开销。再次感谢您。我还有最后一个问题。当我添加
DenseMatrix F=std::move(a*B)时
对于我的代码,我观察到
std::move
导致编译器没有优化代码——也就是说,编译器无法生成
A*B
。因此,如果我理解正确,我应该正确设计move操作(如果我使用指针)并且不应该通过使用
std::move
来干扰编译器的工作。但是我应该在我的move-ctor的初始值设定项中使用它。如果我使用
std::vector
std::unique\u ptr
,我需要写move操作吗?@Arda
std::move(A*B)
static\u cast(A*B)相同
。强制转换会阻止编译器执行返回值优化,因此会导致额外的移动构造。如果您的表达式生成prvalue/xvalue,则不要移动它,因为这会导致您观察到的行为。
unique\u ptr
不可复制,因此在转移所有权时必须移动。使用
vector
这取决于您的目标是什么,您是否也要原始副本?由于评论中的空间限制,我将修改我的问题,以反映我通过您的建议和一些阅读了解到的内容。请您对我问题的最新版本发表意见?
std::cout << "move ctor called. " << this << std::endl;
/* move ctor */
DenseMatrix D( A*B );
std::cout << "&D " << &D << std::endl;
ctor with two arguments called. 0x7fff7c2cb1d0  <-- temporary created in the 
                                                    return statement of operator*
move ctor called. 0x7fff7c2cb2b0                <-- temporary moved into the return value
dtor called. 0x7fff7c2cb1d0                     <-- temporary from step 1 destroyed
move ctor called. 0x7fff7c2cb230                <-- return value moved into D
dtor called. 0x7fff7c2cb2b0                     <-- return value destroyed
&D 0x7fff7c2cb230                               <-- address of D
DenseMatrix::DenseMatrix( DenseMatrix&& rhs ) noexcept :
    m_( std::move(rhs.m_) ), n_( std::move(rhs.n_) ), values( std::move(rhs.values) ) {
//..
}
    DenseMatrix( size_t m, size_t n,
        std::vector< double > values = {} ) : // <-- use list initialization, 
                                              //     no need to repeat type name
        m_( m ),
        n_( n ),
        values_( std::move(values) )          // <-- move the vector instead of copying
    {
        // ...
    }