我只是看下面的代码片段:

#include<iostream>
#include<cstring>
using namespace std;

class String
{
private:
    char *s;
    int size;
public:
    String(const char *str = NULL); // constructor
    ~String() { delete [] s; }// destructor
    void print() { cout << s << endl; }
    void change(const char *); // Function to change
};

String::String(const char *str)
{
    size = strlen(str);
    s = new char[size+1];
    strcpy(s, str);
}

void String::change(const char *str)
{
    delete [] s;
    size = strlen(str);
    s = s + 1;
    s = new char[size+1];
    strcpy(s, str);
}

int main()
{
    String str1("StackOverFlow");
    String str2 = str1;

    str1.print();
    str2.print();

    str2.change("StackOverFlowChanged");

    str1.print();
    str2.print();
    return 0;
}
我期望输出为:
堆栈溢出,
堆栈溢出,
堆栈溢出,
StackOverflowChanged。
str2.change(“StackOverFlowChanged”)行之前,str1和str2的都指向相同的内存位置。但是,在更改方法中,由于指针值已更改,因此我现在除了str1和str2的指向不同的位置,事实并非如此。有人可以解释为什么会这样吗?

最佳答案

调用str2.change之后,str1不再具有有效的指针。由于两个对象共享相同的指针,因此通过删除一个对象中的数组,另一个对象现在指向已删除的数组。尝试访问str1指向的数组是未定义的行为,因此str1.print()是无效的代码。
现在,在这种特殊情况下,很可能new char[]中的str2.change恰好会返回一个指向刚删除的地址的指针。毕竟,只是释放了内存,与此同时没有进行其他分配。因此,尽管str1的指针仍然无效,但恰好可以解决在调用str1.print时指向有效字符串的问题。
但这只是偶然;实现不必这样做。未定义的行为是未定义的,您需要properly follow the Rule of 5。或者只是使用std::string

关于c++ - C++对象复制,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63649053/

10-13 03:34