浅拷贝 指向同一个地址空间
右边不可取地址 左边一定是到了具体的位置
右值引用std:: move
相信大家默认构造函数都没有问题,所以就不贴例子了
浅拷贝构造函数
只负责复制地址,而不是真的把完整的内存给它
#include <iostream>// 浅拷贝是通过默认的复制构造函数来实现的。默认的复制构造函数会逐个复制对象的所有成员变量,但不会复制动态分配的内存。浅拷贝只是复制指针而不复制指针指向的内容。class Shallow {
public:int* data;// 构造函数Shallow(int d) {data = new int(d);}// 浅拷贝构造函数Shallow(const Shallow& source) : data(source.data) {std::cout << "Shallow copy constructor - shallow copy" << std::endl;}// 析构函数~Shallow() {delete data;std::cout << "Destructor freeing data" << std::endl;}
};int main() {Shallow obj1(42);Shallow obj2 = obj1; // 使用浅拷贝构造函数std::cout << "obj1 data: " << *obj1.data << std::endl;std::cout << "obj2 data: " << *obj2.data << std::endl;return 0;
}
深拷贝构造函数
其实跟深拷贝的意思一样,真正的什么都复制
还要分配新的内存
#include <iostream>class Deep {
public:int* data;// 构造函数Deep(int d) {data = new int(d);}// 深拷贝构造函数Deep(const Deep& source) {data = new int(*source.data);std::cout << "Deep copy constructor - deep copy" << std::endl;}// 析构函数~Deep() {delete data;std::cout << "Destructor freeing data" << std::endl;}
};int main() {Deep obj1(42);Deep obj2 = obj1; // 使用深拷贝构造函数std::cout << "obj1 data: " << *obj1.data << std::endl;std::cout << "obj2 data: " << *obj2.data << std::endl;return 0;
}
浅拷贝构造函数的代码会遇到一个问题,就是出现悬空指针,析构的时候会指向同一个指针
而深拷贝就避免了这个问题
为了提升性能,因此就来了新的概念
移动语义
用移动构造函数和移动赋值运算符。
移动构造函数(Move Constructor)是C++11引入的一种特殊构造函数,
用于实现对象资源的高效转移,而不是复制。
它的引入是为了避免不必要的深拷贝,提高程序性能,特别是当处理临时对象时。
移动构造函数的概念
- 移动构造函数允许从一个即将销毁的对象(通常是临时对象)中“窃取”资源,而不是复制资源。
- 移动构造函数接收一个右值引用参数,即将被移动的对象,并将其资源转移到新对象中。
- 移动构造函数通常与移动赋值运算符一起使用,以实现全面的移动语义。
这里建议直接看例子
移动构造函数的语法
移动构造函数的声明使用右值引用参数(通常是 Type&&
),并在实现中转移资源。
#include <iostream>class Mstring {
public:char* data;// 默认构造函数Mstring() : data(nullptr) {std::cout << "Default constructor called" << std::endl;}// 参数构造函数Mstring(const char* str) {if (str) {data = new char[strlen(str) + 1];strcpy(data, str);} else {data = nullptr;}std::cout << "Parameterized constructor called" << std::endl;}// 拷贝构造函数Mstring(const Mstring& source) {if (source.data) {data = new char[strlen(source.data) + 1];strcpy(data, source.data);} else {data = nullptr;}std::cout << "Copy constructor called" << std::endl;}// 移动构造函数Mstring(Mstring&& source) noexcept : data(source.data) {source.data = nullptr;std::cout << "Move constructor called" << std::endl;}// 拷贝赋值运算符Mstring& operator=(const Mstring& source) {if (this == &source)return *this;delete[] data;if (source.data) {data = new char[strlen(source.data) + 1];strcpy(data, source.data);} else {data = nullptr;}std::cout << "Copy assignment operator called" << std::endl;return *this;}// 移动赋值运算符Mstring& operator=(Mstring&& source) noexcept {if (this == &source)return *this;delete[] data;data = source.data;source.data = nullptr;std::cout << "Move assignment operator called" << std::endl;return *this;}// 析构函数~Mstring() {delete[] data;std::cout << "Destructor called" << std::endl;}
};int main() {Mstring str1("Hello");Mstring str2("World");// 使用移动赋值运算符str2 = std::move(str1);std::cout << "After move assignment, str1: " << (str1.data ? str1.data : "nullptr") << std::endl;std::cout << "After move assignment, str2: " << (str2.data ? str2.data : "nullptr") << std::endl;return 0;
}
参数构造函数
参数构造函数是C++类的一种构造函数,
它接受一个或多个参数,
并使用这些参数来初始化类的成员变量。
与默认构造函数(不接受任何参数)相对,
参数构造函数为类的实例提供了一种灵活的初始化方式。
参数构造函数的定义
参数构造函数是在类的定义中声明的构造函数,
其参数列表可以包含一个或多个参数。
通过这些参数,构造函数可以对类的成员变量进行初始化。上面的例子是有体现的
- 默认构造函数:
Mstring()
,不接受任何参数,初始化成员变量data
为nullptr
。 - 参数构造函数:
Mstring(const char* str)
,接受一个const char*
参数,用于初始化成员变量data
。如果参数不为空,则分配足够的内存并复制字符串内容。 - 拷贝构造函数:
Mstring(const Mstring& source)
,用于创建一个现有对象的副本,分配新的内存并复制内容。 - 移动构造函数:
Mstring(Mstring&& source) noexcept
,用于高效地从另一个即将销毁的对象中移动资源,避免了不必要的内存分配和复制。 - 拷贝赋值运算符:用于将一个对象的内容赋值给另一个现有对象,确保正确地处理动态分配的内存。
- 移动赋值运算符:用于将一个即将销毁的对象的内容移动到另一个现有对象,避免不必要的内存分配和复制。
- 析构函数:
~Mstring()
,释放动态分配的内存,避免内存泄漏。 main
函数:演示如何使用参数构造函数创建对象,以及如何使用移动构造函数进行对象移动。
内存提前分配
内存提前分配(Pre-allocation)是指在对象或数据结构初始化时提前分配所需的内存,以减少运行时的分配开销。这在需要处理大量数据或频繁分配和释放内存的场景中特别有用。
参数构造函数中的内存提前分配示例
下面是一个改进的 Mstring
类,展示了如何在参数构造函数中提前分配内存。
#include <iostream>class Array {
private:int* data;size_t size;public:// 参数构造函数:提前分配内存Array(size_t size) : size(size) {data = new int[size]; // 提前分配内存std::cout << "Constructor: Allocated memory for " << size << " integers." << std::endl;}// 析构函数:释放内存~Array() {delete[] data;std::cout << "Destructor: Freed allocated memory." << std::endl;}// 获取数组大小size_t getSize() const {return size;}// 获取数组元素(带边界检查)int getElement(size_t index) const {if (index < size) {return data[index];} else {throw std::out_of_range("Index out of range");}}// 设置数组元素(带边界检查)void setElement(size_t index, int value) {if (index < size) {data[index] = value;} else {throw std::out_of_range("Index out of range");}}
};int main() {// 使用参数构造函数创建一个大小为10的数组Array arr(10);// 设置数组中的元素for (size_t i = 0; i < arr.getSize(); ++i) {arr.setElement(i, i * 2);}// 获取并打印数组中的元素for (size_t i = 0; i < arr.getSize(); ++i) {std::cout << "Element at index " << i << ": " << arr.getElement(i) << std::endl;}// arr对象超出作用域时,会自动调用析构函数释放内存return 0;
}
内存重复利用
1.分配一块内存2构建对象3使用对象4析构对象5销毁内存
1.优先使用dowhile循环
压栈的开销非常大,因此避免重复调用
面向对象和面向过程的区别
面向过程和面向对象的区别-CSDN博客
什么是内联函数
函数移除不必要的多态性 减省空间
性能在面向对象中最顶的
swich 跳转很快
简化表达式+位移算法
IO优化
Vector
list
set/multiset
map/Multiset
选择策略
性能分析工具
Asan
实现原理: 编译的时候。。。方式
Gprof
Valgrind
Perf
能看到函数调用次数
系统资源对性能的影响
进程选取
更新当前任务虚拟时间