C++拷贝控制,移动控制总结

本文深入探讨C++中的各种构造函数,包括普通构造、拷贝构造、移动构造及对应的赋值操作,解析深拷贝与浅拷贝的区别,以及析构函数的工作原理。通过一个简易的vector实现案例,展示了构造与析构在实际应用中的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

普通构造函数:
普通构造函数就没什么好说的了
拷贝构造函数:
当我们需要用一个对象初始化另一个对象时,我们就需要拷贝初始化
在形式上长这样fuck(const fuck& a){}
const不是必须的但是通常情况下是const的

那么什么时候会用到拷贝构造呢,普遍意义下,只用我们需要用一个对象初始化另一个对象时,那么我们就要使用了
比如  
fuck a = fuck(5)  fuck a = c;
值传递时,返回非引用对象时等等
但是有一个问题,就是编译器可能会绕过拷贝构造,这个时候不会显式的调用拷贝构造,不同的编译器处理方式不同
但是这些绕过的操作也需要拷贝构造的存在,比如我们将拷贝构造声明为private,explicit,都会报错

拷贝赋值:
拷贝赋值和拷贝构造差异不大,主要需要注意深拷贝,浅拷贝,自赋值的问题
深拷贝即先备份再赋值,然后释放旧值
浅拷贝直接赋值,释放旧值
自赋值注意下

移动构造:
当我们从一个即将不需要的对象初始化另一个对象时,如果使用拷贝初始化时,会显得太傻
那么移动构造应运而生,移动构造即把一个右值引用对象移动到新的对象中,这个过程没用出现
多余的拷贝操作问题
形式为fuck(const &&a);参数为一个右值引用
库函数std::move可以将一个左值变为右值
移动赋值:
同样注意子赋值的问题

注意:我们一定要保证右值对象移动后,保证其为可析构的,并且是安全的

右值左值:
这两者在c++中的区别比在c中的区别抽象了点,主要时左值用到了对象的身份,而右值用到了值本身或这是一个临时对象
c++中允许向一个右值赋值,我们可以用引用限定符来限定这种操作

析构函数:
下面几种情况会使用析沟函数:
变量离开作用域
对象被销毁时,其成员也被销毁
容器被销毁时,其中的元素会销毁
delete动态分配内存时

注意: 销毁对象,释放内存,这些事不是析沟函数函数体做的事,而是析构函数的另一个阶段

差不多这些就是c++ primer13章学习的感受,收益良多,所以写了写自己粗浅的见解

vector的简易实现:
注意非const static成员要在类外定义,否则链接的时候找不到


#include<iostream>
#include<cstdio>
#include<memory>
#include<string>
using namespace std;
class StrVec
{
public:
	StrVec():elements(nullptr),cap(nullptr),first_free(nullptr){};
	StrVec(initializer_list<string>a):elements(nullptr),cap(nullptr),first_free(nullptr){
		auto be = a.begin();
		for(int i = 0;i<a.size();i++){
			check_n_alloc();
			push_back(*be++);
		}
	}
	StrVec(const StrVec &a);
	StrVec& operator=(const StrVec &a);
	StrVec( StrVec &&a) noexcept;
	StrVec& operator=(StrVec &&a) noexcept;
	~StrVec();
	void push_back(const string& s);
	int size() const{
		return first_free-elements;
	}
	int capacity() const{
		return cap-elements;
	}
	string* begin() const
	{
		return elements;
	}
	string* end() const
	{
		return first_free;
	}
private:
	pair<string*,string*> alloc_n_copy(const string* a,const string *b);
	static allocator<string> alloc;
	string *elements;
	string *cap;
	string *first_free;
	void free();
	void reallocate();
	void check_n_alloc()
	{
		if(size()==capacity()) reallocate();
	}
};
allocator<string> StrVec:: alloc;
StrVec::StrVec(const StrVec &a)
{
	auto data = alloc_n_copy(a.begin(),a.end());
	elements = data.first;
	first_free = cap = data.second;
}
StrVec& StrVec::operator=(const StrVec &a){
	auto data = alloc_n_copy(a.begin(),a.end());
	free();
	elements = data.first;
	first_free = cap = data.second;
	return *this;
}
StrVec::StrVec( StrVec &&a) noexcept{

		elements = a.elements;
		first_free = a.first_free;
		cap = a.cap;
		a.elements  = a.first_free = a.cap = nullptr;
}
StrVec& StrVec::operator=(StrVec &&a) noexcept{
	if(this==&a){

	}
	else{
		elements = a.elements;
		first_free = a.first_free;
		cap = a.cap;
		a.elements  = a.first_free = a.cap = nullptr;
	}
}
StrVec::~StrVec(){
	free();
}
void StrVec::push_back(const string& s){
	check_n_alloc();
	alloc.construct(first_free++,s);
}
pair<string* ,string*> StrVec::alloc_n_copy(const string *a,const string *b)
{
	auto data = alloc.allocate(b-a);
	return {data,uninitialized_copy(a,b,data)};
}
void StrVec::free()
{
	if(elements){
		for(string *i = elements;i!=first_free;i++){
			alloc.destroy(i);
		}
		alloc.deallocate(elements,cap-elements);
	}
}
void StrVec::reallocate()
{
	int new_size = size()?size()*2:1;
	auto data = alloc.allocate(new_size);
	auto new_elements = data;
	auto tmp_elements = elements;
	for(int i = 0;i<size();i++){
		alloc.construct(new_elements++,move(*tmp_elements++));
	}
	free();
	elements = data;
	first_free = new_elements;
	cap = data+new_size;
}
int main()
{
	 StrVec a({"ffsfsf","fsfsf","fffff"});
	 a.push_back("ffff");
	 cout<<a.size()<<endl;
	 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值