【C++】使用容器管理对象注意事项

本文探讨了C++中对象浅拷贝导致的析构陷阱,解释了在C++11和C++03版本中如何通过使用移动构造函数和智能指针避免重复析构的问题。在C++11中,利用默认的移动构造函数和unique_ptr可以高效解决;而在C++03版本,需要自定义拷贝构造函数进行深度复制。
摘要由CSDN通过智能技术生成

标题取的不太恰当,实际是:对象浅拷贝的陷阱。

将局部对象变量放入容器中进行管理需要特别小心(存在重复析构成员变量为指针类型的属性),直接上代码看:

#include <vector>
#include <string>
#include <iostream>
using namespace std;

class Person {
public:
	Person(string name) : pName_(new string(name)) {}
	// Person(const Person& person);
	~Person() { 
		cout << *pName_ << " deleted" << endl;
		delete pName_; 
	}
	void printName() { cout << *pName_ << endl; }

private:
	string* pName_;
};

int main() {
	vector<Person> persons;
	Person p("George");
	persons.push_back(p);

	persons.front().printName();

	cout << "Goodbye " << endl;
	
	return 0;
}

在main函数return前:
1.向量对象persons会被析构,并且其中的元素也会调用对应的析构函数进行析构(调用~Person);
2.局部对象p也会被析构;

初看好像没有什么问题,但是局部对象b会被编译器默认的拷贝构造函数(Copy constructer)浅拷贝一份放入persons向量中。如此b对象的string *pName_指针同时被2个对象拥有,那么就存在~Person()重复delete pName_的现象

 在C++11版本中如何处理这个问题?

使用移动构造函数 + 智能指针: 效率高,不用重复创建pName_ 。

#include <vector>
#include <string>
#include <iostream>
using namespace std;

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

	Person(Person&&) = default;
	void printName() { cout << *pName_ << endl; }

private:
	std::unique_ptr<string> pName_;  // 使用shared_ptr有点浪费
};

int main() {
	vector<Person> persons;
	Person p("George");
	persons.push_back(std::move(p));
	// p 对象被Move Construct,已经不能使用
	persons.front().printName();

	cout << "Goodbye " << endl;
	
	return 0;
}

在C++03版本中如何处理这个问题?

不采用编译器提供的默认“拷贝构造函数、赋值构造函数”,类中存在指针属性,直接使用默认的这2个构造函数是非常危险的。直接显示编写这2个构造函数!

效率没有C++11版高(这就体现了移动构造的高效率),其他无差异。

#include <vector>
#include <string>
#include <iostream>
using namespace std;

class Person {
public:
	Person(string name) : pName_(new string(name)) {}
	Person(const Person& person){
		this->pName_ = new string(*person.pName_);
	}
	~Person() {
		cout << *pName_ << " deleted" << endl;
		delete pName_;
	}

	Person(Person&&) = default;
	void printName() { cout << *pName_ << endl; }

private:
	string* pName_;
};

int main() {
	vector<Person> persons;
	Person p("George");
	persons.push_back(p);  // 使用自定义的拷贝构造函数深度复制p对象

	persons.front().printName();

	cout << "Goodbye " << endl;
	
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值