我正在阅读引子中的一个例子,它所谈到的事情并没有发生.具体来说,任何隐式浅拷贝都应该复制指针的地址,而不仅仅是指向的值(因此是相同的内存地址).但是,每个pos属性都指向两个不同的内存地址(因此我可以更改一个值而不影响另一个).我究竟做错了什么?
头
#include "stdafx.h"
#include <iostream>
class Yak
{
public:
int hour;
char * pos;
const Yak & toz(const Yak & yk);
Yak();
};
Run Code Online (Sandbox Code Playgroud)
结束标题
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;
}
Run Code Online (Sandbox Code Playgroud)
sbi*_*sbi 11
您正在打印指针的地址,而不是它们指向的字符串的地址:
cout << &blak.pos << endl;
cout << &tom.pos << endl;
Run Code Online (Sandbox Code Playgroud)
它们是两个不同的指针,因此它们的地址不同.但是,它们指向相同的字符串:
cout << static_cast<void*>(blak.pos) << endl;
cout << static_cast<void*>(tom.pos) << endl;
Run Code Online (Sandbox Code Playgroud)
(注意,演员static_cast<void*>(tom.pos).正如Aaron在评论中指出的那样,因为当输出一个char*遗嘱时operator<<,流库将假定该字符指向一个以零结尾的字符串的第一个字符.输出一个void*,OTOH,将输出地址.)
请注意,您的代码存在更多错误.这里
Yak tom;
Run Code Online (Sandbox Code Playgroud)
您正在创建一个新对象.它的构造函数分配20个字符,并将其地址存储在tom.pos.在下一行
tom.pos="Hi";
Run Code Online (Sandbox Code Playgroud)
您正在分配字符串文字tom.pos的地址,从而丢弃您分配的字节的地址,从而有效地泄漏了该内存.
还要注意,Yak没有析构函数,所以即使你没有丢弃那20个字符,当tom超出范围时,tom.pos也会被破坏,从而丢失那20个字节的地址.
但是,由于您缺少复制构造函数,当您复制Yak对象时,最终会有两个pos元素指向相同的已分配内存.当他们超出范围时,他们都试图删除那个致命的内存.
削减这个短:使用std::string.这更容易.掌握基本知识,使用语言的安全功能,如std::string标准库的容器,智能指针.一旦您对这些内容有所了解,请解决手动内存管理问题.
但是,请记住,在做C++约15年之后,我认为手动资源管理(内存只是一种资源)容易出错,并试图避免它.如果我必须这样做,我会将每个资源隐藏在管理它的对象后面 - 有效地回退到自动内存管理.:)
您正在阅读哪个"入门"?Lippmann的C++入门?如果是这样,哪个版本?如果最近一版Lippmann的书能让你在没有首先展示你的工具来解决这个问题以及如何使用它们的情况下让你失去动态记忆,我会感到惊讶.