当绑定到功能参数时,为什么移动的类对象不会触发移动构造器?
假设
- 我有一个非平凡的类对象
a
定义复制和移动构造函数, - 我将此对象移动到
a
或a&& ;
现在,如果foo
的参数类型为a
,则称为MOVE构造器(这可以预期为a&&
作为参数传递给函数本地a)。
但是,在a&&
的情况下,移动构造函数是 not 调用的,实际上没有调用构造函数。为什么?
我本可以认为这是由于复制责任而发生的,但是它也发生在GCC的-O0标志设置时。我也认为& amp;基本上只是flags
参数列表中的过载分辨率的RVALUE,因为在功能主体内部,它被视为LVALUE。但这意味着lvalue a
将绑定移动的a&&
,并且应该再次调用移动构造函数。我想念什么?
根据x86-x64 GCC 11.2编译
#include <iostream>
#include <string>
#include <string.h>
struct A
{
char * str_;
A() {
std::cout << "normal constructor called\n";
str_ = new char[7];
sprintf(str_, "Hello!");
}
~A(){ delete[] str_; }
A(A& copy) {
std::cout << "copy constructor called\n";
str_ = strdup(copy.str_);
}
A(A&& moved) {
std::cout << "move constructor called\n";
str_ = moved.str_;
moved.str_ = nullptr;
}
};
void foo(A&& a)
{
std::cout << a.str_ << "\n";
}
int main()
{
A obj;
foo(std::move(obj));
}
Lets say
- I have a non-trivial class object
A
that defines a copy and move constructor - I move this object to a function which takes either
A
orA&&
Now in case of foo
's parameter type being A
, the move constructor is called (this is to be expected as A&&
is passed as an argument to the function-local A).
But in case of A&&
, the move constructor is not called, and in fact no constructor is called. Why?
I would have assumed that this happens because of copy elision, but it also happens with the -O0 flag set for gcc. I also thought that && basically just flags
an rvalue for overload resolution in the parameter list because inside the function body, it is treated as an lvalue. But this would mean that an lvalue A
would bind a moved A&&
and the move constructor should be called once again. What am I missing?
Compiled under x86-x64 gcc 11.2
#include <iostream>
#include <string>
#include <string.h>
struct A
{
char * str_;
A() {
std::cout << "normal constructor called\n";
str_ = new char[7];
sprintf(str_, "Hello!");
}
~A(){ delete[] str_; }
A(A& copy) {
std::cout << "copy constructor called\n";
str_ = strdup(copy.str_);
}
A(A&& moved) {
std::cout << "move constructor called\n";
str_ = moved.str_;
moved.str_ = nullptr;
}
};
void foo(A&& a)
{
std::cout << a.str_ << "\n";
}
int main()
{
A obj;
foo(std::move(obj));
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当
foo
采用a&amp;&amp;
时,您将绑定到R-Value引用,而不制作任何需要构造的新a
对象。<<<<<<<<<<<<<<<<<<<<<<< br>这是因为
std ::移动
基本上只是r-value参考的铸件。当
foo
采用a
时,您将r值引用转到a
作为构造a
的一种手段。在这里,选择移动构造函数是因为它将a&amp;&amp;
作为其参数。When
foo
takesA&&
, you are binding to a r-value reference and not making any newA
objects that need construction.This is because
std::move
is basically just a cast to r-value reference.When
foo
takesA
, you are passing a r-value reference toA
as a means of constructingA
. Here, the move constructor is chosen as it takesA&&
as its argument.