我正在阅读底漆中的一个示例,但它所谈论的事情并没有发生。具体来说,任何隐式浅拷贝都应该在指针的地址上复制,而不仅仅是指向的对象的值(因此具有相同的内存地址)。但是,每个pos属性都指向两个不同的内存地址(因此我能够更改一个的值而不会影响另一个)。我究竟做错了什么?

header

#include "stdafx.h"
#include <iostream>

class Yak
{
public:
    int hour;
    char * pos;
    const Yak & toz(const Yak & yk);
    Yak();
};

结束标题
using namespace std;
const Yak & Yak:: toz(const Yak & yk)
{
    return *this;
}

Yak::Yak()
{
    pos = new char[20];

}

int _tmain(int argc, _TCHAR* argv[])
{
    Yak tom;
    tom.pos="Hi";

    Yak blak = tom.toz(tom);


    cout << &blak.pos << endl;
    cout << &tom.pos << endl;


    system("pause");
    return 0;
}

最佳答案

您正在打印指针的地址,而不是它们指向的字符串的地址:

cout << &blak.pos << endl;
cout << &tom.pos << endl;

它们是两个不同的指针,因此它们的地址不同。但是,它们指向相同的字符串:
cout << static_cast<void*>(blak.pos) << endl;
cout << static_cast<void*>(tom.pos) << endl;

(请注意,强制转换static_cast<void*>(tom.pos)。正如Aaron在评论中指出的那样,这是必要的,因为当通过char*输出operator<<时,流库将假定指向的字符为零终止字符串的第一个字符。输出void* OTOH将输出地址。)

请注意,您的代码还有更多错误。这里
Yak tom;

您正在创建一个新对象。它的构造函数分配20个字符,并将其地址存储在tom.pos中。在下一行
tom.pos="Hi";

您将字符串文字的地址分配给tom.pos,从而丢弃分配的字节的地址,从而有效地泄漏了该内存。

还要注意Yak没有析构函数,因此即使您不以这种方式丢弃20个字符,当tom超出范围时,tom.pos也将被破坏,因此这20个字节的地址将丢失。

但是,由于缺少复制构造函数,因此在复制Yak对象时,最终会导致其中两个对象的pos元素指向相同的已分配内存。当它们超出范围时,它们都将尝试删除该内存,这是致命的。

简短说明:使用std::string。这要容易得多。使用std::string,stdandard库的容器,智能指针等语言的安全功能来掌握基础知识。一旦确定这些内容后,就可以进行手动内存管理。

但是,请记住,我从事C++大约15年,考虑手动资源管理(内存只是一种资源)容易出错,并尝试避免这种情况。如果必须这样做,我会将每个资源隐藏在管理它的对象后面-有效地退回到自动内存管理。 :)
您正在阅读哪个“入门”? Lippmann的C++入门书?如果是这样,哪个版本?如果Lippmann的最新版本会让您迷失在动态内存中而没有先展示解决该问题的工具以及如何使用它们,我会感到惊讶。

关于c++ - 关于复制构造函数和指针,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3241307/

10-11 15:17
查看更多