最近在学习 C++ primer,在读到 copy-control 这一章节是对指针有了些疑惑,还请大家帮助解答。 这个是书中对 copy assignment operator 的实现,
HasPtr& operator=(const HasPtr &hp) {
auto new_p = new std::string(*hp.ps);
delete ps;
ps = new_p;
i = hp.i;
return *this;
}
这个是我自己的实现,
HasPtr &HasPtr::operator=(const HasPtr &hp)
{
if (this != &hp)
{
*ps = *hp.ps;
i = hp.i;
}
return *this;
}
两者的区别是,书中的实现方式是先 new 了一个局部指针当内存申请成功后,再删除旧指针指向的对象,并把旧指针指向新指针的位置,我的实现是直接修改指针指向的 string 对象,从而更改值。我想知道我这种方法的缺陷在哪里,为什么不能直接更改指针所指向的对象,而是要新建一个临时指针,还请大家帮助我
全部实现代码
class HasPtr
{
public:
HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) {}
HasPtr(const HasPtr &);
string GetString() { return *ps; };
HasPtr &operator=(const HasPtr &);
~HasPtr() { delete ps; }
private:
std::string *ps;
int i;
};
HasPtr::HasPtr(const HasPtr &orig) : ps(new std::string(*orig.ps)), i(orig.i)
{
}
HasPtr &HasPtr::operator=(const HasPtr &hp)
{
auto new_p = new string(*hp.ps);
delete ps;
ps = new_p;
i = hp.i;
return *this;
}
1
AlohaV2 2019-08-10 22:43:42 +08:00 via Android
|
2
Tony042 OP @AlohaV2 不好意思,刚才没有放出全部代码
```C++ class HasPtr { public: HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) {} HasPtr(const HasPtr &); string GetString() { return *ps; }; HasPtr &operator=(const HasPtr &); ~HasPtr() { delete ps; } private: std::string *ps; int i; }; HasPtr::HasPtr(const HasPtr &orig) : ps(new std::string(*orig.ps)), i(orig.i) { } HasPtr &HasPtr::operator=(const HasPtr &hp) { auto new_p = new string(*hp.ps); delete ps; ps = new_p; i = hp.i; return *this; } ``` 这两个指针我在初始化的时候已经指向了不同的地址,我感觉我在做*this.ps=*hp.ps 的时候是将 this 指向的地址的内容改变了,是改变了 this.ps 指向的 string 的值,而并没有改变指针的值,也就是说并没有改变指针的地址,所以不会造成悬挂指针吧? |
3
choury 2019-08-11 00:33:41 +08:00
缺陷倒是没啥缺陷,就是用你这个方法作例子的话不怎么通用,因为你能这样做是因为 string 重载了=,并且如果 ps 是 const 指针,你就没办法这么干了
|
4
bccoder 2019-08-11 01:11:54 +08:00 via iPhone
你的 ps 之前如果指向有效地址的话在重新赋值前应该 delete 掉之前的,不知是否正确?
|
5
across 2019-08-11 01:37:54 +08:00
例子是深拷贝。你的是浅拷贝,按你做法,包含这么一个指针成员时,再调用赋值,两个类内部指向的是同一个指针对象,在哪个类的析构函数里面释放这个对象内存呢?
|
6
across 2019-08-11 01:39:25 +08:00
另外,编译器默认生成的就是浅拷贝,所以你这个实现,其实还不用写····
(我应该没记错来着) |
7
Tony042 OP |
8
AlohaV2 2019-08-11 07:27:10 +08:00 via Android
@Tony042 你的实现应该是浅拷贝。如果换成你的实现,可以试试
HasPtr foo; {//scpoed HasPtr bar; foo =bar; } // bar dtor string fools = foo.GetString(); 这样会不会出错。并且 foo 构造时申请出的 ps 内存是泄露的。 |
9
gggxxxx 2019-08-11 07:39:18 +08:00
楼主的实现确实是深拷贝,也是很常用的一种思路和策略。
楼主的做法和书里做法区别在于,楼主的方案需要依赖 std::string 的拷贝是深拷贝实现。书里的做法不需要依赖。 |
10
Tony042 OP @AlohaV2 我刚才试了下,没问题的,可以成功拷贝数据,GetString 也可以正常输出数据,bar 和 foo 也正常析构了。
|
11
Tony042 OP @gggxxxx 我也觉得是这样,之前 google 了不少,发现大家都是书中这种做法,就搞得我有点懵,久闻 C++深坑居多,怕不小心一脚踩进去,就发帖来问问大家,谢谢层主的回答
|
12
chashao 2019-08-11 08:21:54 +08:00 via iPhone
原来 ps 指向的 string 是不是没释放?
|
13
AlohaV2 2019-08-11 08:33:45 +08:00
|
14
Tony042 OP @AlohaV2 还有一个问题求问,改变了 string 的值后,之前那个 string 是不是已经被释放了,没有出现内存泄漏吧?还是有点虚
|
15
AlohaV2 2019-08-11 08:39:50 +08:00 1
@Tony042 之前的 string (代码里的 *hp。ps)会在它自己析构的时候通过上面写的析构函数~HasPtr()释放,这边赋值的时候不会释放。
|
16
liberize 2019-08-11 09:49:24 +08:00 via Android
你写的没有问题
|