day09了 加油

发布于:2024-07-03 ⋅ 阅读:(11) ⋅ 点赞:(0)

浅拷贝 指向同一个地址空间

右边不可取地址 左边一定是到了具体的位置

右值引用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(),不接受任何参数,初始化成员变量 datanullptr
  • 参数构造函数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

能看到函数调用次数

系统资源对性能的影响

进程选取

更新当前任务虚拟时间

异构cpu+多频率带

内存管理


网站公告

今日签到

点亮在社区的每一天
去签到