智能指针可以放到容器中么_C++11新特性6 - 容器与带指针属性的类

e01c98c3e018e42e63324b25b6cabd34.png

本文主要介绍 C++ 中使用容器和拥有指针作为属性的类容易遇到的问题,以及 C++11 新的解决思路

在 C++03 中使用带指针属性的类

假如我们定义了这样一个类

class Person {
public:
  Person(const string& name) {
    pName = new string(name);
  }
  ~Person() {delete pName;}
  string *pName;
};

我们希望把这个类放到 vector 里面,于是写出了一段看上去似乎没问题,但事实上会崩溃的代码

int main() {
  vector<Person> persons;
/*
这个 push_back 会发生三件事情:
1. 构造一个 pName 指向 "Bob" 的 Person
2. 讲这个对象浅拷贝到 persons[0] 位置
3. 析构生成 1 中生成的 Person, 释放"Bob"
*/
  persons.push_back(Person("Bob"));
  
  return 0;
} 
// persons 析构
// 已被释放的 "Bob" 再次被释放,程序崩溃

为了避免这个问题,在 C++03 中,常见的解决方法是给 Person 添加一个拷贝构造函数

Person(const Person& rhs) {
  pName = new string(*rhs.pName);
}

然而,使用这种方法时,"Bob" 被多余地构造和释放了一次,造成了浪费

C++11 的解决方法

C++11 中,解决这个问题最简单的方法是,使用 emplace_back 替换 push_back,让容器自己来构造对象

int main() {
  vector<Person> persons;

  // 在 persons 内部生成 Bob
  persons.emplace_back("Bob");

  return 0;
} 

C++11 中,各种容器的插入,都实现了 emplace 版本

然而,如果我们一定要使用 push_back,注意到 Person("Bob") 是个右值,由于 C++11 重载了右值版本的 push_back(T&&),我们给 Person 添加移动构造函数

Person(Person&& rhs) {
  pName = rhs.pName;
  rhs.pName = nullptr;
}

这样,push_back 内部只会发生两次指针赋值操作,而不是重新构造一个字符串

那么,使用智能指针能不能解决这个问题呢?答案是可以的,两种解决方法

// 1. 使用 shared_ptr
class Person {
public:
  Person(const string& name):
    pName(new string(name)) {}
  shared_ptr<string> pName;
};

// 2. 使用 unique_ptr
class Person {
public:
  Person(const string& name):
    pName(new string(name)) {}
  unique_ptr<string> pName;
};

要注意的是, 如果使用 shared_ptr,每次拷贝之后 pName 指向的字符串事实上是共享的;如果使用 unique_ptr,则 Person 是不可拷贝只可移动的

本文主要翻译自 Bo Qian 的 YouTube 视频

C++ 11: Resource Managing Class​youtu.be
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值