Cpp-04-拷贝构造
拷贝构造函数
一般来说,编译器会提供一个默认的拷贝构造函数,即使我们定义了其他构造函数,默认的拷贝构造会将参数的非static成员逐个拷贝到正在创建的对象中。对于类类型的成员,会使用类的拷贝构造函数进行拷贝,内置类型的成员则直接拷贝。(行为像值的类就是深拷贝)
- 使用=号定义变量。
- 将一个对象作为实参传递给非引用类型的形参。
- 从一个返回类型为非引用类型的函数返回一个对象。
- 用{}列表初始化一个数组或一个聚合类的成员。
某些类对他们分配的对象使用拷贝初始化,如使用容器或调用其insert或push成员时(使用emplace创建都是直接初始化)。
class mystring{ private: char *str; /* data */ public: mystring() : str(nullptr){} mystring(const mystring &mystr) { if (&mystr == this) { return; } if (mystr.str == nullptr) { str = nullptr; return; } size_t len = strlen(mystr.str); str = new char[len + 1]; strcpy(str, mystr.str); } mystring(const char *mystr) { // 注意:使用 const char* 而不是 char* if (mystr == nullptr) { str = nullptr; return; } size_t len = strlen(mystr); str = new char[len + 1]; strcpy(str, mystr); } //重载= mystring &operator=(const mystring &mystr) { if (&mystr == this) { return *this; } // 释放旧内存 delete[] str; if (mystr.str == nullptr) { str = nullptr; return *this; } size_t len = strlen(mystr.str); str = new char[len + 1]; strcpy(str, mystr.str); return *this; } //默认析构函数不会回收指针指向的空间 // ~mystring() = default; //一般来说,如果定义了析构函数,也需要实现拷贝构造和拷贝赋值,因为默认是浅拷贝,会一起析构掉。 ~mystring(){ delete[] str; // 使用 delete[] 来释放数组分配的内存 str = nullptr; } //重载<< friend ostream &operator<<(ostream &os, mystring &mystr); } //完善友元函数 ostream &operator<<(ostream &os, mystring &mystr){ if(mystr.str == nullptr){ os << "mystring_ data is null" << endl; return os; } os << "mystring_ data is " << mystr1.m_str << endl; return os; } void initBase(){ //直接初始化 auto mystr1 = mystring("hello world!"); //直接初始化 auto mystr2(mystr1); //默认初始化 auto mystr3 = mystring(); //拷贝初始化 auto mystr4 = mystr3; //拷贝初始化 auto mystr5 = "hello world!"; //拷贝初始化 auto mystr6 = mystring("hello world!"); cout << mystr1 << mystr2 << mystr3 << endl; }
单例模式
#include <iostream> #include <memory> #include <mutex> class Singleton_ { public: // 删除拷贝构造函数和赋值操作符 Singleton_(const Singleton_&) = delete; Singleton_& operator=(const Singleton_&) = delete; // 获取单例实例 static std::shared_ptr<Singleton_> getinstance() { // 如果非空直接返回不加锁节省效率 if (_inst == nullptr) { std::call_once(_init_flag, []() { _inst = std::make_shared<Singleton_>(); }); } return _inst; } //等价于使用双重检查锁 static std::shared_ptr<Singleton_> getinstance() { // 第一次检查:如果非空直接返回,避免不必要的锁开销 if (_inst == nullptr) { std::lock_guard<std::mutex> lock(_mutex); // 第二次检查:确保在多线程环境下只有一个实例被创建 if (_inst == nullptr) { _inst = std::make_shared<Singleton_>(); } } return _inst; } private: // 私有构造函数,确保只能通过 getinstance() 创建实例 Singleton_() {} // 静态成员变量初始化 static std::shared_ptr<Singleton_> _inst; static std::once_flag _init_flag; static std::mutex _mutex; }; // 在类外部初始化静态成员变量 std::shared_ptr<Singleton_> Singleton_::_inst = nullptr; std::once_flag Singleton_::_init_flag; int main() { auto instance1 = Singleton_::getinstance(); auto instance2 = Singleton_::getinstance(); if (instance1 == instance2) { std::cout << "Both instances are the same." << std::endl; } else { std::cout << "Instances are different." << std::endl; } return 0; }
简单的共享指针
class SharePtr{
private:
string *pstr;
std::atomic<size_t> *pcount;
public:
SharePtr() : pstr(nullptr), pcount(new std::atomic<size_t>(0));
explicit SharePtr(const string &str) : pstr(new string(str)), pcount(new std::atomic<size_t>(1)){}
//拷贝构造函数,自我赋值检查是多余的
SharePtr(const SharePtr &sptr) : pstr(sptr.pstr), pcount(sptr.pcount){
if(pcount != nullptr){
(*pcount)++;
}
}
SharePtr(const SharePtr &&sptr) noexcept : pstr(sptr.pstr), pcount(sptr.pcount){
sptr.pstr = nullptr;
sptr.pcount = nullptr;
}
SharePtr &operator=(const SharePtr &sptr){
if(this != &sptr){
//减少引用计数
if(pcount != nullptr && --(*pcount) == 0){
delete pstr;
delete pcount;
}
pstr = sptr.pstr;
pcount = sptr.pcount;
if(pcount != nullptr){
(*pcount)++;
}
}
return *this;
}
SharePtr &operator=(SharePtr &&sptr) noexcept{
if(this != &sptr){
//减少引用计数
if(pcount != nullptr && --(*pcount) == 0){
delete pstr;
delete pcount;
}
pstr = sptr.pstr;
pcount = sptr.pcount;
sptr.pstr = nullptr;
sptr.pcount = nullptr;
}
return *this;
}
~SharePtr(){
if (pcount != nullptr && --(*pcount) == 0) {
delete pstr;
delete pcount;
}
}
size_t getUseCount() const {
return pcount ? *pcount : 0;
}
//解引用
string &operator*() const {
return *pstr;
}
string *operator->() const {
return pstr;
}
explicit operator bool() const {
return pstr != nullptr;
}
}
swap
using std::swap;
class HasPtr
{
public:
// 默认构造函数
HasPtr() : m_str(new string()), m_index(0) { ++_curnum; }
// 构造函数,从字符串初始化
explicit HasPtr(const string &str) : m_str(new string(str)), m_index(0) { ++_curnum; }
// 析构函数
~HasPtr() {
delete m_str;
--_curnum;
}
// 拷贝构造函数
HasPtr(const HasPtr &hp) : m_str(new string(*hp.m_str)), m_index(hp.m_index) { ++_curnum; }
HasPtr &operator=(const HasPtr &hp){
cout << "this is operator = " << endl;
if (&hp != this){
// 先删除旧的字符串,再创建新的
delete m_str;
m_str = new string(*hp.m_str);
m_index = hp.m_index;
}
return *this;
}
friend ostream &operator<<(ostream &os, const HasPtr &);
// 友元函数 swap
friend void swap(HasPtr &ptr1, HasPtr &ptr2) noexcept {
using std::swap;
swap(ptr1.m_str, ptr2.m_str);
swap(ptr1.m_index, ptr2.m_index);
}
private:
string *m_str;
int m_index;
static int _curnum;
};
// 实现友元函数 << 操作符
ostream &operator<<(ostream &os, const HasPtr &hp) {
os << "String: " << *hp.m_str << ", Index: " << hp.m_index;
return os;
}
//等价于这个,新版本的operator=参数为HasPtr类型,而不是引用类型,这样hptr是赋值运算符右侧变量的副本
//随着函数返回,那么形参也就会自动销毁了
HasPtr &HasPtr::operator=(HasPtr hptr)
{
// hptr是一个局部变量
//交换后hptr.m_str指向this.m_str原来指向的内存
swap(*this, hptr);
// return返回*this后,hptr自动被回收
return *this;
}