C++11智能指针

Smart pointer 会不会比Raw pointer效率低?

  • 想把智能指针用成瓶颈的话,基本上是不可能的,不要过度担心

Smart pointer 不用自己管理内存了,是不是对c++程序员要求低了

  • 显然是要求更高了,想要用好智能指针的前提是会熟练使用裸指针,而且要了解智能指针的实现原理,要根据实际情况去选择shared_ptr及unique_ptr。智能指针使用不当同样会内存泄漏

 

unique_ptr使用

unique 顾名思义 ownership 唯一

1.推荐使用make_unique进行初始化(C++14)

std::unique_ptr<int> pTest = std::make_unique<int>(3);

2. 函数传递时避免使用unique_ptr作为函数参数,除非需要转移所有权到函数里面,一般通过Get函数获取裸指针去传递

void func1(std::unique_ptr<int> p){
	*p = 10;
}

void func2(int* p) {
	*p = 10;
}

int main() {
	std::unique_ptr<int> pInt = std::make_unique<int>(3);
	func2(pInt.get());
}

如果一定要使用unique_ptr进行传递,可以选择使用引用(不推荐,原因见文章末尾)

#include <memory>
void func1(std::unique_ptr<int>& p){
	*p = 10;
}

int main() {
	std::unique_ptr<int> pInt = std::make_unique<int>(3);
	func1(pInt);
}

3.unique_ptr经常作为返回值使用,设计模式中经常用到,异常安全

如工厂模式

class PizzaFactory {
public:
	enum PizzaType {
		HamMushroom,
		Deluxe,
		Hawaiian
	};

	static unique_ptr<Pizza> createPizza(PizzaType pizzaType) {
		switch (pizzaType) {
		case HamMushroom: return make_unique<HamAndMushroomPizza>();
		case Deluxe:      return make_unique<DeluxePizza>();
		case Hawaiian:    return make_unique<HawaiianPizza>();
		}
		throw "invalid pizza type.";
	}
};

或者Prototype原型模式

class RecordFactory
{
private:
	unordered_map<RecordType, unique_ptr<Record>, hash<int> > m_records;

public:
	RecordFactory()
	{
		m_records[CAR]    = make_unique<CarRecord>("Ferrari", 5050);
		m_records[BIKE]   = make_unique<BikeRecord>("Yamaha", 2525);
		m_records[PERSON] = make_unique<PersonRecord>("Tom", 25);
	}

	unique_ptr<Record> createRecord(RecordType recordType)
	{
		return m_records[recordType]->clone();
	}
};

 

 

shared_ptr

  • 我用c++开发服务器端时,因为要并发,经常用到shared_ptr
  • 初始化同样使用make_shared
std::shared_ptr<int> pInt = std::make_shared<int>(3);
  • 避免循环引用的坑(你中有我,我中有你。解决方法是将其中一个改成weak_ptr)
struct A;
struct B;
struct B {
	std::shared_ptr<int> pA;
};
struct A {
	std::shared_ptr<int> pB;
};
  • 使用智能指针时,避免使用new 裸指针
  • 我喜欢将shared_ptr 放到std::vector<>中 ~ ~

 

备注:什么时候用shared_ptr,什么时候用unique_ptr?

  • 判别很简单,就是ownership,独占所有权就用unique_ptr ,共享就shared
  • 想不明白的时候,我一般先会使用uniqe_ptr ,当编译器编译不通过的时候,我再换shared_ptr
  • 0或者直接用shared_ptr ,后期再重构

 

注意事项:

参数传递时,尽量不要使用智能指针的引用

分两种情况讨论:shared_ptr与unique_ptr。shared_ptr本身就不必要传递引用,因为不会发生所有权变化。而就unique_ptr来说,传递引用会造成:

  • 接受引用方对此资源是否具有所有权?如果有,则破坏了unique_ptr的独一所有权语义,应考虑move或者换成shared_ptr;如果没有,应考虑传递裸指针而非传递引用。
  • 接受引用方会否将资源长期持有?比如多线程之间资源传递。若有,该资源生命周期不被引用方控制,会造成隐形bug。

总结:正确使用智能指针的方式是

  1. 在函数中作为参数传递是,尽量避免使用智能指针,使用*或者引用,跟以前一样
  2. 尽量使用unique_ptr,他比shared_ptr更light
  3. 尽量使用makeshared/ make_unique 来代替new
  4. 不出现new 和 delete

C++11智能指针

 

 

上一篇:【C++札记】C++智能指针


下一篇:C++11特性-智能指针详解