当绑定到功能参数时,为什么移动的类对象不会触发移动构造器?

发布于 2025-01-22 06:04:40 字数 1358 浏览 1 评论 0原文

假设

  • 我有一个非平凡的类对象a定义复制和移动构造函数,
  • 我将此对象移动到aa&& ;

现在,如果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 or A&&

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?

CODE

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一身仙ぐ女味 2025-01-29 06:04:40

foo采用a&amp;&amp;时,您将绑定到R-Value引用,而不制作任何需要构造的新a对象。<<<<<<<<<<<<<<<<<<<<<<< br>
这是因为std ::移动基本上只是r-value参考的铸件。
foo采用a时,您将r值引用转到a作为构造a的一种手段。在这里,选择移动构造函数是因为它将a&amp;&amp;作为其参数。

When foo takes A&&, you are binding to a r-value reference and not making any new A objects that need construction.
This is because std::move is basically just a cast to r-value reference.
When foo takes A, you are passing a r-value reference to A as a means of constructing A. Here, the move constructor is chosen as it takes A&& as its argument.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文