智能指针
c++中,我们可以使用new
delete
关键字来从heap上分配内存。
然而,有时候我们会忘记delete
,所以有了智能指针。
智能指针有三类unique_ptr,shared_ptr,weak_ptr
unique_ptr
在当前作用域创建的unique_ptr
,在作用域结束时会自动销毁分配内存。
shared_ptr
所有指向同一个对象的 shared_ptr指针,只有在所有的 shared_ptr
离开作用域后,才会自动销毁
weak_ptr
同shared_ptr
,但是不会增加计数器的技术,当所有shared_ptr
离开作用域后,即使weak_pointer
仍然存在,也会自动销毁指向对象。
#include <iostream>
class Entity {
public:
Entity() {
std::cout << "create Entity!" << std::endl;
}
~Entity() {
std::cout << "destroy Entity!" << std::endl;
}
void print() {
}
};
int main() {
{
std::shared_ptr<Entity> shared_pointer;
{
std::shared_ptr<Entity> e0 = std::make_shared<Entity>();
shared_pointer = e0;
}
}
{
//std::shared_ptr<Entity> shared_pointer(new Entity());//导致分配2次,影响性能
std::weak_ptr<Entity> weak_pointer;
{
std::shared_ptr<Entity> e0 = std::make_shared<Entity>();
weak_pointer = e0;
}
}
{
//std::unique_ptr<Entity> entity(new Entity); //可能有异常安全问题
std::unique_ptr<Entity> entity = std::make_unique<Entity>();
}
}
拷贝构造函数
拷贝构造函数涉及复制时发生浅拷贝(拷贝指针对象时只拷贝指针)
和深拷贝(拷贝指针对象时,不仅拷贝指针,还额外拷贝了指针所指向对象)
的问题。
#include <iostream>
#include <string>
class String {
private:
size_t m_size;
char* m_buffer;
public:
String(const char* string) {
m_size = strlen(string);
m_buffer = new char[m_size + 1];
memcpy(m_buffer, string, m_size);
m_buffer[m_size] = '\x00';
}
String(const String& other) :m_size(other.m_size) { //拷贝构造函数,深拷贝
m_buffer = new char[m_size + 1];
memcpy(m_buffer, other.m_buffer, m_size + 1);
}
char& operator[](const size_t index) {
return m_buffer[index];
}
friend std::ostream& operator<<(std::ostream & stream, const String& string);
~String() {
delete[] m_buffer;
}
};
std::ostream& operator<<(std::ostream & stream,const String& string) {
stream << string.m_buffer;
return stream;
}
int main() {
String e("wsxk");
String e1(e);
e[2] = 's';
std::cout << e << std::endl;
std::cout << e1 << std::endl;
}
->重载
#include <iostream>
#include <string>
class Entity {
private:
int x;
public:
void print() {
std::cout << "hello" << std::endl;
}
};
class ScopePtr {
private:
Entity* m_entity;
public:
ScopePtr(Entity* m_obj) : m_entity(m_obj) {
}
~ScopePtr() {
delete m_entity;
}
Entity* operator->() {
return m_entity;
}
};
int main() {
ScopePtr entity = new Entity();//隐式转换
entity->print();//箭头操作符重载
}
std::vector
#include <iostream>
#include <vector>
class Vertex {
public:
float x, y, z;
};
std::ostream& operator<<(std::ostream& stream, const Vertex& vertex) {
stream << vertex.x << "," << vertex.y << "," << vertex.z;
return stream;
}
int main() {
std::vector<Vertex> vertices;
vertices.push_back({ 1,2,3 });
vertices.push_back({ 4, 5, 6 });
for (int i = 0; i < vertices.size(); i++) {
std::cout << vertices[i] << std::endl;
}
vertices.erase(vertices.begin() + 1);
for (int i = 0; i < vertices.size(); i++) {
std::cout << vertices[i] << std::endl;
}
}
std::vector优化
#include <iostream>
#include <vector>
class Vertex {
public:
float x, y, z;
Vertex(const Vertex& vertex) : x(vertex.x), y(vertex.y), z(vertex.z) {
std::cout << "vertex copyed!" << std::endl;
}
Vertex(float a,float b,float c) : x(a), y(b), z(c) {
}
};
std::ostream& operator<<(std::ostream& stream, const Vertex& vertex) {
stream << vertex.x << "," << vertex.y << "," << vertex.z;
return stream;
}
int main() {
std::vector<Vertex> vertices;
vertices.push_back({ 1,2,3 });
vertices.push_back({ 4, 5, 6 });
vertices.push_back({ 7,8,9 });
}
实际上会copy 6次。
预设容量后,减少一半
#include <iostream>
#include <vector>
class Vertex {
public:
float x, y, z;
Vertex(const Vertex& vertex) : x(vertex.x), y(vertex.y), z(vertex.z) {
std::cout << "vertex copyed!" << std::endl;
}
Vertex(float a,float b,float c) : x(a), y(b), z(c) {
}
};
std::ostream& operator<<(std::ostream& stream, const Vertex& vertex) {
stream << vertex.x << "," << vertex.y << "," << vertex.z;
return stream;
}
int main() {
std::vector<Vertex> vertices;
vertices.reserve(3);
vertices.push_back({ 1,2,3 });
vertices.push_back({ 4, 5, 6 });
vertices.push_back({ 7,8,9 });
}
通过不在栈上创建Vertex
,直接传参进入,就不用发生拷贝
#include <iostream>
#include <vector>
class Vertex {
public:
float x, y, z;
Vertex(const Vertex& vertex) : x(vertex.x), y(vertex.y), z(vertex.z) {
std::cout << "vertex copyed!" << std::endl;
}
Vertex(float a,float b,float c) : x(a), y(b), z(c) {
}
};
std::ostream& operator<<(std::ostream& stream, const Vertex& vertex) {
stream << vertex.x << "," << vertex.y << "," << vertex.z;
return stream;
}
int main() {
std::vector<Vertex> vertices;
vertices.reserve(3);
vertices.emplace_back(1, 2, 3);
vertices.emplace_back(4, 5, 6);
vertices.emplace_back(7, 8, 9);
}
template
template是c++一个强大的特性
它可以减少我们的代码重复,比如书写一个打印不同类型值的函数的时候
#include <iostream>
#include <string>
template<typename T>
void print(T value) {
std::cout << value << std::endl;
}
int main() {
print(1);
print<int>(0.5);
print("hello");
}
template实际上做的是,当遇到一个类型时,会自动把该类型填入到T中,并生成相应的代码,如下:
#include <iostream>
#include <string>
template<typename T>
void print(T value) {
std::cout << value << std::endl;
}
void print(int value) {
std::cout << value << std::endl;
}
void print(std::string value) {
std::cout << value << std::endl;
}
void print(float value) {
std::cout << value << std::endl;
}
int main() {
print(1);
print<int>(0.5); // <int>可以显式得指定模板的类型
print(0.5f);
print("hello");
}
template还能做到很多有趣的事情,比如自动填写类
比如我们想要一个可以动态调整数组大小的类,我们可以这样用
#include <iostream>
#include <string>
template<int N>
class Array {
private:
int m_array[N];
public:
int GetSize() { return N; }
};
int main() {
Array<5> a;
std::cout << a.GetSize() << std::endl;
}
更进一步,如果我们想要数组存储的不一定是int类型的整数,还可以是其他类型时,我们可以这样用
#include <iostream>
#include <string>
template<typename T,int N>
class Array {
private:
T m_array[N];
public:
int GetSize() { return N; }
};
int main() {
Array<float,5> a;
std::cout << a.GetSize() << std::endl;
}
十分高级
std::array
std::array
位于<array>
这个标准库中,它是一个静态数组,一旦确认,不能更改大小
#include <iostream>
#include <array>
#include <vector>
template <int N> //这里使用template是为了让传参时不必把5写上去
void PrintArray(std::array<int, N>& a) {
for (int i = 0; i < a.size(); i++) {
std::cout << a[i] << std::endl;
}
}
int main() {
std::array<int, 5> data;
data[0] = 1;
data[4] = 5;
PrintArray(data);
}
std::array在栈上分配,然而不分配内存来存储size
因为 _Size
是一个模板,所以在代码使用它后,他会实际填到这个函数中,也就说,这个函数返回一个常数,因此不需要内存来存储size.
std::array可以有边界检查,当然是可选的
array 和 vector的区别
实际上区别如下:
- array是静态数组,vector是动态的
- array在栈上分配,vector在heap中分配,因此用array会比vector快