注册 登录
编程论坛 C++教室

关于string的移动构造

leeco 发布于 2023-05-06 17:49, 661 次点击
在观察string移动构造时发现一个问题,为什么移动构造前后原来应该被置空的对象的c_str()没有变化,而且新构造的对象的c_str()和原对象不等呢?
我期望的行为应该和我自己实现的String对象的行为类似啊
程序代码:

#include "bits/stdc++.h"
using namespace std;

class String {
public:
    String() {
        cout << "String()" << endl;
    }
    String(const char* p) {
        cout << "String(const char* p)" << endl;
        this->len = strlen(p);
        this->p = new char[this->len + 1];
        strcpy(this->p, p);
    }

    String(const String& s) {
        cout << "String(const String& s)" << endl;
        this->len = s.len;
        this->p = new char[this->len + 1];
        strcpy(this->p, s.p);
    }

    String(String&& s) {
        cout << "String(String&& s)" << endl;
        this->len = s.len;
        this->p = s.p;
        s.p = nullptr;
        s.len = 0;
    }

    ~String() {
        cout << "~String()" << endl;
        if(this->p) {
            delete this->p;
        }
    }

    String& operator = (const String& s) {
        cout << "String& operator = (const String& s)" << endl;
        if(this->p) {
            delete this->p;
        }
        this->len = s.len;
        this->p = new char[this->len + 1];
        strcpy(this->p, s.p);
        return *this;
    }

    String& operator = (String&& s) {
        cout << "String& operator = (String&& s)" << endl;
        if(this->p) {
            delete this->p;
        }
        this->len = s.len;
        this->p = s.p;
        s.p = nullptr;
        s.len = 0;
        return *this;
    }

    const char* c_str() const {
        return p;
    }


private:
    char* p = nullptr;
    int len = 0;

    friend ostream& operator << (ostream& out, const String& s);
};

ostream& operator << (ostream& out, const String& s) {
    if(s.c_str()) {
        out << s.c_str();
    } else {
        out << "";
    }
    return out;
}

void test1() {
    String a = "abc";
    printf("%p\n", a.c_str());
    String b = move(a);
    printf("%p\n", a.c_str());
    printf("%p\n", b.c_str());
    cout << a << endl;
    cout << b << endl;
    move(b);
    cout << b << endl;
}

void test2() {
    using String = std::string;

    String a = "abc";
    printf("%p\n", a.c_str());
    String b = move(a);
    printf("%p\n", a.c_str());
    printf("%p\n", b.c_str());
    cout << a << endl;
    cout << b << endl;
    move(b);
    cout << b << endl;
}

int _main_() {
    test1();
    test2();

    return 0;
}

2 回复
#2
后卿2023-05-06 17:57
移动构造是什么名词,没听过,是复制构造吗
#3
rjsp2023-05-06 18:25
这是因为 std::string 使用了 Small String Optimization。

BTW:
#include "bits/stdc++.h" 这种非标的东西很令人厌恶,你若是写成 import std; 的话,即使我用不了,但也无法抱怨
constexpr、noexcept 这两个关键字能用就得用.
String(const char* p) 中 new,若new异常,但这个对象却创建了。应该放在初始化列表中。(类似的地方略)
int len = 0; 应该是 size_t len = 0;
if(this->p) 是多余的,因为 delete (TYPE*)nullptr; 是良好定义行为
String& operator = (const String& s) 你有没有考虑过自己给自己赋值?(类似的地方略)
const char* c_str() const 空字符串应该返回"",而非 nullptr
friend ostream& operator << (ostream& out, const String& s); 自定义类型时不能省略std::,不能强迫别人必须使用 using namespace std;
test1() 与 test2() 基本一样,最好用 template
int _main_() 给别人的代码,应当保证别人无须修改即可编译
1