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

普通构造函数:
普通构造函数就没什么好说的了
拷贝构造函数:
当我们需要用一个对象初始化另一个对象时,我们就需要拷贝初始化
在形式上长这样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;
	 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 概述 在C++语言中,拷贝语义和移动语义是与对象拷贝相关的两个核心概念,它们分别决定了如何高效地复制对象。 #### 拷贝语义 (Copy Semantics) 拷贝语义是传统的复制机制,用于复制(`copy`)、赋值(`assignment`)以及通过值传递的对象。它包括三种形式: 1. **拷贝构造函数** (`Copy Constructor`) - 当使用新的对象初始化另一个已存在的对象或创建新对象时调用。 ```cpp MyClass(const MyClass& other); ``` 2. **赋值运算符** (`Assignment Operator`) - 将一个对象的值赋予另一个对象。 ```cpp MyClass& operator=(const MyClass& other); ``` 3. **拷贝赋值运算符** (`Copy Assignment Operator`) - 类似于`operator=`,但在某些情况下,为了性能优化,可以提供专用版本。 ```cpp MyClass& operator=(MyClass&& other); // 使用移动语义时提供此版本 ``` 拷贝语义通常涉及资源的浅复制或深复制,这取决于所处理对象的数据结构特性。 #### 移动语义 (Move Semantics) 移动语义是为了提高性能而引入的一种更先进的复制机制。相比拷贝语义,移动操作会将对象的一部分或全部状态从源对象转移到目标对象,同时尽量减少内存分配和拷贝操作。 移动语义涉及到以下关键概念: 1. **移出构造函数** (`Move Constructor`) - 当需要从其他非临时对象移动资源而不是拷贝时使用。 ```cpp MyClass(MyClass&& other) noexcept; ``` 2. **移动赋值运算符** (`Move Assignment Operator`) - 同样是在某些情况下为了提高效率,可以提供专门的移动赋值运算符。 ```cpp MyClass& operator=(MyClass&& other); // 代替拷贝赋值运算符 ``` 移动语义的核心优势在于减少了不必要的拷贝和内存分配,特别是在大对象或多线程环境下能显著提升程序性能。 ### 应用场景及优缺点 - **优点**:移动语义可以大幅提高代码的运行效率,在处理大型数据结构或在高并发环境中特别有效。 - **缺点**:引入移动语义后,代码需要额外关注哪些地方应该使用移动构造和赋值,这可能会增加编写和维护代码的复杂度,并可能导致错误如未声明的移动操作或不当的拷贝操作。 ### 相关问题: 1. **移动语义何时优先于拷贝语义?** 这种情况通常出现在资源密集型的应用中,特别是当对象很大或需要频繁复制时,移动语义能够显著提高性能。 2. **如何在实际项目中应用移动语义?** 需要识别潜在的移动候选者,通常是那些包含大量资源的类或容器,评估是否可以在构造函数、赋值运算符或析构函数中应用移动语义。 3. **移动语义与拷贝语义之间的交互是如何管理的?** 确保正确的使用移动语义需要理解两者之间的区别和相互作用,避免在不应使用移动的地方使用,同时合理利用拷贝语义保证程序的兼容性和健壮性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值