尽管传递了右值,为什么我的move构造函数没有被调用?

时间:2019-05-15 08:43:10

标签: c++ c++11 move move-semantics move-constructor

我通过定义默认,复制和移动构造函数来创建类字符串。我尝试创建期望每个构造函数都被调用的对象。正如预期的那样,将调用默认的&复制构造函数,但是当我传递一个rvalue(临时对象)时,我仍然看到未调用move构造函数。

#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
}

s1 :正在按预期调用默认构造函数

s2 :也按预期方式调用复制构造函数

s3 :我正在传递一个临时对象。因此,我希望调用 move构造函数,但是会调用默认构造函数

我无法理解我所缺少的。请帮助,谢谢。

2 个答案:

答案 0 :(得分:3)

您已将data定义为char *

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

表示move构造函数中data的“副本”不是深层副本。

编辑:现在可以了,因为您可以“破坏”右值,但是,当它析构函数时,您可以使用nullptr

致电时

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

在析构函数中,数据为空,您具有未定义的行为。什么都可能发生。

答案 1 :(得分:1)

实际上,它的行为与您在GCC和Clang中所说的一样,但是move构造函数是在VC ++中调用的。看起来像个错误,然后应该使用std :: move()明确移动。