首页 > 解决方案 > 类动态分配的字符数组中的 WTF 行为

问题描述

每次运行下面的代码时,我都会崩溃应用程序。在调试过程中,我看到该str对象在main(). 这对我来说是个谜。尝试自己运行它:

#include<iostream>

class String {
private:
    char* string = nullptr;
    int length = 0;

public:
    String(const char str[]) {
        for (length; str[length] != '\0'; ++length);

        string = new char[length + 1]{};

        for (int i{}; i < length; ++i)
            string[i] = str[i];

        string[length] = '\0';
    }

    ~String() {
        delete[] string;
    }

    auto print() {
        for (int i{}; i < length; ++i)
            std::cout << string[i];
        std::cout << '\n';
        return *this;
    }

    auto getStrPtr() {
        return string;
    }
};

int main() {
    String str("123");
    auto strPtr{ str.print().getStrPtr() };
    strPtr[0] = '3';
}

我错过了什么吗?

注意第 2 行main():我正在尝试打印str'string数组,然后,由于print()返回*this,我可以链接方法并调用返回string' 指针的函数。但是,即使在调试器中它都能完美执行,我也不知道为什么地狱str对象会在之后解构自己。

标签: c++classdynamic-memory-allocation

解决方案


str对象不会在 的第二行被销毁main。的临时副本str被销毁。

临时对象在完全表达结束时被销毁。这个是正常的。


您的类在析构函数中删除了一个指针成员,但未能保持该指针唯一性的类不变性。str当析构函数删除与临时对象的析构函数删除相同的指针值时,程序的行为是不确定的。strPtr[0] = '3';甚至在此之前,当通过在析构函数中删除的指针进行间接操作时,行为也是未定义的。

解决方案:不要使用拥有裸指针。请改用智能指针或容器。std::string这里似乎合适。


但是为什么首先要创建这个临时对象呢?

因为你Stringprint. 您用 初始化它*this,因此该对象是一个副本。您不使用返回的对象来初始化变量,因此会物化一个临时对象。


推荐阅读