简体   繁体   English

尽管传递了一个右值,为什么我的移动构造函数不会被调用?

[英]Despite passing an rvalue, why isn't my move constructor getting called?

I create a class string by defining default, copy & move constructor. 我通过定义默认,复制和移动构造函数来创建一个类字符串。 I try to create objects expecting each constructor to be invoked. 我尝试创建期望每个构造函数被调用的对象。 As expected, the default & copy constructor are invoked, but when I pass a rvalue(temporary object), I still see move constructor NOT being invoked. 正如所料,默认&复制构造函数被调用,但是当我传递一个rvalue(临时对象)时,我仍然看到移动构造函数未被调用。

#include <iostream>
#include <cstdlib>
#include <cstring>

class string
{
    char * data;
public:
    string(const char * p = nullptr)
    {
        if(p == nullptr) return;
        std::cout << "string(const char * p)" << std::endl;
        size_t size = strlen(p) + 1;
        data = new char[size];
        memcpy(data, p, size);
    }
    ~string()
    {
        std::cout << "~string() - " << data << std::endl;
        delete[] data;
    }
    string(const string & that)
    {
        std::cout << "string(const string &)" << std::endl;
        size_t size = strlen(that.data) + 1;
        data = new char[size];
        memcpy(data, that.data, size);
    }
    string(string && that)
    {
        std::cout << "string(string && )" << std::endl;
        data = that.data;
        that.data = nullptr;
    }
    void showData() { std::cout << data << std::endl; }
    string operator+(const string & other)
    {
        size_t datasize = strlen(data);
        size_t othersize = strlen(other.data);
        size_t totalsize = datasize + othersize + 1;
        char * sData = new char[totalsize];
        memcpy(sData, data, strlen(data));
        memcpy(sData+datasize, other.data, totalsize-datasize);
        string s(sData);
        delete[] sData;
        return s;

    }
    string & operator=(string that)
    {
        char * tmp = data;
        data = that.data;
        that.data = tmp;
        return *this;
    }
};

int main()
{
    string s1{"stackoverflow"};  // s1
    string s2{s1};               // s2
    string s3{string("stack")+string("exchange")};  // s3
}

At s1 : default constructor is being called as expected. s1 :正在按预期调用默认构造函数

At s2 : copy constructor is invoked, also as expected. s2 :调用复制构造函数 ,也如预期的那样。

At s3 : I'm passing a temporary object. s3 :我正在传递一个临时物体。 So, I expect move constructor be invoked, but default constructor being called. 所以,我希望调用move构造函数 ,但调用默认构造函数

I'm unable to comprehend what I'm missing. 我无法理解我所缺少的东西。 Kindly help, thanks. 请帮助,谢谢。

You have defined data as a char * . 您已将data定义为char *

string(string && that)
{
    std::cout << "string(string && )" << std::endl;
    data = that.data;
    that.data = nullptr;
}

means that the "copy" of data in the move constructor isn't a deep copy. 表示移动构造函数中的data “副本”不是深层副本。

Edit: Now, that would be ok, since you can "gut" the rvalue, however, when it destructors you do this using a nullptr : 编辑:现在,这没关系,因为你可以“消除”右边界,但是,当它破坏你使用nullptr这样做时:

When you call 你打电话的时候

std::cout << "~string() - " << data << std::endl;

in the destructor, data is null, you have undefined behaviour. 在析构函数中,data为null,您有未定义的行为。 Anything could happen. 什么事情都可能发生。

Indeed it behaves as you say with GCC and Clang, but the move constructor is called with VC++. 实际上它的行为和GCC和Clang一样,但是用VC ++调用移动构造函数。 Looks like a bug, then you should move explicitly with std::move(). 看起来像一个bug,然后你应该用std :: move()显式移动。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM