1.唯一性智能指针的删除器
class Object
{
public:
Object() {}
Object() = default;
};
template<class _Ty>
class MyDeletor
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete ptr;
}
}
};
template<class _Ty>
class MyDeletor<_Ty[]>
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete[] ptr;
}
}
};
int main()
{
MyDeletor<Object> op;
MyDeletor<Object[]> arop;
Object* p = new Object(10);
op(p);
p = new Object[10];
arop(p);
return 0;
}
2.画出下面函数的内存分布图
class Object
{
public:
Object() {}
Object() = default;
};
template<class _Ty>
class MyDeletor
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete ptr;
}
}
};
template<class _Ty>
class MyDeletor<_Ty[]>
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete[] ptr;
}
}
};
template<class _Ty,class _Dx = MyDeletor<_Ty>>
class my_unique_ptr
{
public:
using pointer = _Ty*;
using element_type = _Ty;
using delete_type = _Dx;
private:
_Ty* _Ptr;
_Dx _myDeletor;
public:
my_unique_ptr(pointer _P = nullptr) :_Ptr(_P) {}
~my_unique_ptr()
{
if (_Ptr != nullptr)
{
_myDeletor(_Ptr);
_Ptr = nullptr;
}
}
my_unique_ptr(my_unique_ptr&& _Y)
{
_Ptr = _Y._Ptr;
_Y._Ptr = nullptr;
}
my_unique_ptr& operator=(my_unique_ptr&& _Y)
{
if(this == &_Y)
return *this;
}
};
int main()
{
my_unique_ptr<Object> op(new Object(10));
return 0;
}
op在析构的时候调用~my_unique_ptr()函数,_myDeletor是一个对象,对象加()调用的是对象的仿函数(operator()函数)
如果将拷贝构造函数和赋值函数删除掉,将无法使用拷贝构造函数和赋值函数
my_unique_ptr(cosnt my_unique_ptr&) = delete;
my_unique_ptr& operator=(cosnt my_unique_ptr&) = delete;
int main()
{
my_unique_ptr<Object> op1(new Object(10));
my_unique_ptr<Object> op2(op1);
my_unique_ptr<Object> op3;
op3 = op1;
return 0;
}
在上面代码的基础上,下面funa和funb函数哪个不能编译通过?
my_unique_ptr<Object> funa()
{
my_unique_ptr<Object> op(new Object(10));
return op;
}
my_unique_ptr<Object> funb()
{
return my_unique_ptr<Object>(new Object(10));
}
答案:funa不能通过,op是一个有名对象,返回的时候要构建临时对象,会调用拷贝构造函数,但是拷贝构造函数已经被删掉了,所以不能编译通过,funb返回的是一个无名对象,无名对象是一个右值对象,调用的是右值构造(移动构造),所以funb可以编译通过
3.唯一性智能指针的所有代码(处理的是单个对象)
class Object
{
public:
Object() {}
Object() = default;
};
template<class _Ty>
class MyDeletor
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete ptr;
}
}
};
template<class _Ty>
class MyDeletor<_Ty[]>
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete[] ptr;
}
}
};
template<class _Ty,class _Dx = MyDeletor<_Ty>>
class my_unique_ptr
{
public:
using pointer = _Ty*;
using element_type = _Ty;
using delete_type = _Dx;
private:
_Ty* _Ptr;
_Dx _myDeletor;
public:
my_unique_ptr(cosnt my_unique_ptr&) = delete;
my_unique_ptr& operator=(cosnt my_unique_ptr&) = delete;
my_unique_ptr(pointer _P = nullptr) :_Ptr(_P) {}
~my_unique_ptr()
{
if (_Ptr != nullptr)
{
_myDeletor(_Ptr);
_Ptr = nullptr;
}
}
my_unique_ptr(my_unique_ptr&& _Y)
{
_Ptr = _Y._Ptr;
_Y._Ptr = nullptr;
}
my_unique_ptr& operator=(my_unique_ptr&& _Y)
{
if (this == &_Y)
return *this;
reset(_Y.release());
return *this;
}
_Dx& get_deletor() const
{
return _myDeletor;
}
const _Dx& get_deletor() const
{
return _myDeletor;
}
_Ty& operator*() const
{
return *_Ptr;
}
pointer opeartor->() const
{
return &**this;
}
pointer get() const
{
return _Ptr;
}
operator bool()const
{
return _Ptr != nullptr;
}
pointer release()
{
_Ty* old = _Ptr;
_Ptr = nullptr;
return old;
}
void reset(pointer _P = nullptr)
{
pointer old = _Ptr;
_Ptr = _P;
if (old != nullptr)
{
_myDeletor(old);
}
}
void swap(my_unique_ptr _Y)
{
std::swap(_Ptr, _Y._Ptr);
std::swap(_myDeletor, _Y._myDeletor);
}
};
template<class _Ty,class ... _Type>
my_unique_ptr<_Ty> my_make_unique(_Type&& ... _arys)
{
return my_unique_ptr<_Ty>(new _Ty(_arys...));
}
4.唯一性智能指针的所有代码(处理的是一个数组)
class Object
{
public:
Object() {}
Object() = default;
};
template<class _Ty>
class MyDeletor<_Ty[],_Dx>
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete ptr;
}
}
};
template<class _Ty>
class MyDeletor<_Ty[]>
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete[] ptr;
}
}
};
template<class _Ty,class _Dx = MyDeletor<_Ty>>
class my_unique_ptr
{
public:
using pointer = _Ty*;
using element_type = _Ty;
using delete_type = _Dx;
private:
_Ty* _Ptr;
_Dx _myDeletor;
public:
my_unique_ptr(cosnt my_unique_ptr&) = delete;
my_unique_ptr& operator=(cosnt my_unique_ptr&) = delete;
my_unique_ptr(pointer _P = nullptr) :_Ptr(_P) {}
~my_unique_ptr()
{
if (_Ptr != nullptr)
{
_myDeletor(_Ptr);
_Ptr = nullptr;
}
}
my_unique_ptr(my_unique_ptr&& _Y)
{
_Ptr = _Y._Ptr;
_Y._Ptr = nullptr;
}
my_unique_ptr& operator=(my_unique_ptr&& _Y)
{
if (this == &_Y)
return *this;
reset(_Y.release());
return *this;
}
_Dx& get_deletor() const
{
return _myDeletor;
}
const _Dx& get_deletor() const
{
return _myDeletor;
}
_Ty& operator*() const
{
return *_Ptr;
}
pointer opeartor->() const
{
return &**this;
}
pointer get() const
{
return _Ptr;
}
operator bool()const
{
return _Ptr != nullptr;
}
pointer release()
{
_Ty* old = _Ptr;
_Ptr = nullptr;
return old;
}
void reset(pointer _P = nullptr)
{
pointer old = _Ptr;
_Ptr = _P;
if (old != nullptr)
{
_myDeletor(old);
}
}
void swap(my_unique_ptr _Y)
{
std::swap(_Ptr, _Y._Ptr);
std::swap(_myDeletor, _Y._myDeletor);
}
_Ty& operator[](size_t _Idx) const
{
return _Ptr[_Idx];
}
};
template<class _Ty,class ... _Type>
my_unique_ptr<_Ty> my_make_unique(_Type&& ... _arys)
{
return my_unique_ptr<_Ty>(new _Ty(_arys...));
}
处理数组和处理单个对象的区别是处理数组的唯一性智能指针重载了一个下标运算符,但是它不能处理数组越界的问题
5.可变参数
template<class _Ty>
void fun(_Ty a) {}
template<class _Ty,class _Uy>
void fun(_Ty a,_Uy b) {}
template<class _Ty,class _Uy,class _Ry>
void fun(_Ty a,_Uy b,_Ry c) {}
template<class ..._Ty>
void fun(_Ty... arg) {}
int main()
{
fun(12);
fun(12,23.34);
fun(12,'a',23.34);
fun(12,23,34,45,'a',23.34);
}
void funa(…) {} funa函数中的…是什么意思?可变参数,代表可以接受任意多个参数,可以没有,可以是一个,也可以是两个,也可以是很多个,传递的时候它可以自己识别参数的个数和类型
void funa(...) {}
int main()
{
fun(12);
fun(12,23.34);
fun(12,'a',23.34);
return 0;
}
移动构造和移动赋值的意义是,将A对象的资源交给B对象,而A将不获得这个资源
6.以值返回,返回会产生一个临时对象,调用移动构造函数,将opa的资源交给临时对象,然后临时对象再将资源交给op1对象,其实编译会对其进行优化,创建的临时对象其实就是op1,也就是返回的时候调用移动构造函数,将opa的资源直接交给op1对象
my_unique_ptr<Object> fun()
{
my_unique_ptr<Object> opa(new Object(10));
return opa;
}
int main()
{
my_unique_ptr<Object> op1 = fun();
return 0;
}
7.具体分析下面代码
my_unique_ptr<Object> fun()
{
my_unique_ptr<Object> opa(new Object(10));
return opa;
}
int main()
{
my_unique_ptr<Object> op1;
op1 = fun();
return 0;
}
先构建op1对象,对应第1行 然后调用fun函数,要想创建opa对象,先创建Object对象,对应2、3行 当以值返回的时候,产生一个临时对象,调用移动构造函数,将opa的资源交给临时对象,对应第4行 fun函数结束,调用opa的析构函数,对应第5行 当把临时对象赋值给op1对象时,调用移动赋值函数,对应第6行 赋值以后,析构临时对象,对应第7行 析构Object对象 析构op1对象
8.如果将fun函数以引用的形式返回,能否编译通过?
my_unique_ptr<Object> & fun()
{
my_unique_ptr<Object> opa(new Object(10));
return opa;
}
int main()
{
my_unique_ptr<Object> op1;
op1 = fun();
return 0;
}
答案:不能编译通过 编译器会提示“尝试引用已删除的函数”,如果以引用返回,返回的是opa的地址,opa变成一个左值,不会在产生临时对象,当把opa的资源交给op1的时候,opa已经被析构掉了,所以不能编译通过
9.如果以右值引用返回可以编译通过吗?
my_unique_ptr<Object>&& fun()
{
my_unique_ptr<Object> opa(new Object(10));
return opa;
}
int main()
{
my_unique_ptr<Object> op1;
op1 = fun();
return 0;
}
答案:不能编译通过 opa是具名对象,具名对象不具有右值返回能力,但是如果强转成右值就可以了,将return opa;改为return std::move(opa);就可以编译通过了,但是它存在一个很严重的问题——op1并不能获取到opa的资源,因为fun函数结束后,opa的资源已经被释放掉了,所以不能用这种方式
创建op1对象,对应第1行 调用fun函数,先创建Object对象,再创建opa对象,对应第2、3行 返回的时候以右值返回,将对象opa强转成右值引用的方式返回,但是此时opa的生存期到了,先析构opa,再析构Object,将opa的资源释放掉,对应第4、5行 返回到主函数以后,调用移动赋值函数,但是此时资源已经被释放了,所以op1并不能获取opa的资源,对应第6行 最后析构op1对象,对应第7行
注意:所以对于具名对象来说,使用引用返回和右值引用返回都是错误的 10.以无名对象的形式返回
my_unique_ptr<Object> fun()
{
return my_unique_ptr<Object> (new Object(10));
}
int main()
{
my_unique_ptr<Object> op1;
op1 = fun();
cout << op1->Value() << endl;
return 0;
}
先构建op1对象,对应第1行 调用fun函数,先构建Object对象,再构建无名对象,对应第2、3行 返回到主函数以后,把无名对象的资源交给op1,调用的是移动赋值函数,对应第4行 这时,无名对象的生存期到了,析构无名对象,对应第5行(注意:此时Object并不因为无名对象的析构而析构,因为现在op1对象拥有这个资源,只有op1对象析构的时候才会去析构Object对象) 打印op1的Value域的值,对应第6行 主函数结束后,调用Object的析构函数,然后调用op1的析构函数,对应第7、8行 如果以引用形式返回或者以右值引用的形式返回,会出现什么问题?
答案:如果以引用形式返回或者以右值引用的形式返回,就是这个无名对象具有名了,就不按照移动方式把资源交给op1,返回的是不是对象的本身,而是返回的是这个对象的地址,fun函数结束后,会把这个对象的资源释放掉,回到主函数后,由于资源已经被释放了,op1也就不能获取资源了,所以会导致opa的资源无法交给op1
注意:不要以引用或者右值引用的形式返回一个具名对象或者不具名对象,这都是错误的
11.工厂方法模式
简单工厂模式虽然简单,但是存在一个很严重的问题,当系统中需要引入新产品时,由于静态工厂方法通过所传入参数的不同来创建不同的产品,这必定要修改工厂类的源代码,将违背“开闭原则”,如何实现增加新产品而不影响已有代码?——工厂方法模式应运而生
日志记录器的设计 Sunny软件公司欲开发一个系统运行日志记录器(Logger),该记录器可以通过多种途径保存系统的运行日志,如通过文件记录或数据库记录,用户可以通过修改配置文件灵活的更改日志记录方式,再设计各类日志记录器时,Sunny公司的开发人员发现需要对日志记录器进行一些初始化工作,初始化参数的设置过程较为复杂,而且某些参数的设置有严格的先后次序,否则可能会发生记录失败,如何封装记录器的初始化过程并保证多种记录器切换的灵活性是Sunny公司开发人员面临的一个难题
Sunny公司的开发人员通过对该需求进行分析,返现该日志记录器有两个设计要点: ①需要封装日志记录器的初始化过程,这些初始化工作较为复杂,例如需要初始化其他相关的类,还有可能需要读取配置文件(例如连接数据库或创建文件),导致代码较长,如果将它们都写在构造函数中,会导致构造函数数庞大,不利于代码的修改和维护 ②用户可能需要更换日志记录方式,再客户端代码中需要提供一种灵活的方式来选择日志记录器,尽量在不修改源代码的基础上更换或者增加日志记录方式
Sunny公司开发人员最初使用简单工厂模式对日志记录器进行了设计,初始结构如图所示 在上面图中,LoggerFactory充当创建日志记录器的工厂,提供了工厂方法createLogger()用于创建日志记录器,Logger是抽象日志记录器接口,其子类为具体日志记录器
在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构,工厂方法模式定义如下:
工厂方法模式(Factory Methed Pattern):定义一个用于创建对象的接口,让子类决定将哪一个实例化,工厂方法模式让一个类的实例化延迟到其子类,工厂方法模式又简称工厂模式(Factory Pattern),又可称作虚拟构造器模式(Vitual Constructor Pattern)或多态工厂模式(Polymrephic Factory Pattern),工厂方法模式是一种类创建型模式
工厂方法模式提供一个抽象工厂接口来声明抽象工厂方法,而由其子类来具体实现工厂方法,创建具体的产品对象,工厂方法模式接口如图所示: 在工厂方法模式结构图中包含如下几个角色: ①Product(抽象产品):它是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类 ②ConcreteProduct(具体产品):它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应 ③Factory(抽象工厂):在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个产品,抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口 ④ConcreteFactory(具体工厂):它是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法, 并可由客户端调用,返回一个具体产品类的实例
与简单工厂模式相比,工厂方法模式最重要的区别是引入了抽象工厂角色,抽象工厂可以是接口,也可以是抽象类或者具体类
完整工厂方法模式结构图 my_unique_ptr的.h文件
#ifndef MY_UNIQUE_PTR_H
#define MY_UNIQUE_PTR_H
template<class _Ty>
class MyDeletor
{
public:
MyDeletor() {}
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete ptr;
}
}
};
template<class _Ty>
class MyDeletor<_Ty[]>
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete[]ptr;
}
}
};
template<class _Ty,class _Dx = MyDeletor<_Ty> >
class my_unique_ptr
{
public:
using pointer = _Ty*;
using element_type = _Ty;
using delete_type = _Dx;
private:
_Ty* _Ptr;
_Dx _myDeletor;
public:
my_unique_ptr(const my_unique_ptr&) = delete;
my_unique_ptr& operator=(const my_unique_ptr&) = delete;
my_unique_ptr(pointer _P = nullptr) :_Ptr(_P) { cout << "my_unique_ptr: " << this << endl; }
~my_unique_ptr()
{
if (_Ptr != nullptr)
{
_myDeletor(_Ptr);
_Ptr = nullptr;
}
cout << "~my_unique_ptr: " << this << endl;
}
my_unique_ptr(my_unique_ptr&& _Y)
{
_Ptr = _Y._Ptr;
_Y._Ptr = nullptr;
cout << " move copy my_unique_ptr : " << this << endl;
}
template<class _Uy>
my_unique_ptr& operator=(_Uy* _p )
{
if (this->_Ptr ==(_Ty*) _p) return *this;
if (_Ptr != nullptr) { _myDeletor(_Ptr); }
_Ptr = _p;
return *this;
}
my_unique_ptr& operator=(my_unique_ptr&& _Y)
{
if (this == &_Y) return *this;
reset(_Y.release());
cout << " move opertor=: " << endl;
return *this;
}
_Dx & get_deleter()
{
return _myDeletor;
}
const _Dx& get_deleter() const
{
return _myDeletor;
}
_Ty& operator*() const
{
return *_Ptr;
}
pointer operator->() const
{
return &**this;
}
pointer get() const
{
return _Ptr;
}
operator bool() const
{
return _Ptr != nullptr;
}
pointer release()
{
_Ty* old = _Ptr;
_Ptr = nullptr;
return old;
}
void reset(pointer _P = nullptr)
{
pointer old = _Ptr;
_Ptr = _P;
if (old != nullptr)
{
_myDeletor(old);
}
}
void swap(my_unique_ptr _Y)
{
std::swap(_Ptr, _Y._Ptr);
std::swap(_myDeletor, _Y._myDeletor);
}
};
template<class _Ty, class _Dx >
class my_unique_ptr<_Ty[],_Dx>
{
public:
using pointer = _Ty*;
using element_type = _Ty;
using delete_type = _Dx;
private:
_Ty* _Ptr;
_Dx _myDeletor;
public:
my_unique_ptr(const my_unique_ptr&) = delete;
my_unique_ptr& operator=(const my_unique_ptr&) = delete;
my_unique_ptr(pointer _P = nullptr) :_Ptr(_P) {}
~my_unique_ptr()
{
if (_Ptr != nullptr)
{
_myDeletor(_Ptr);
_Ptr = nullptr;
}
}
my_unique_ptr(my_unique_ptr&& _Y)
{
_Ptr = _Y._Ptr;
_Y._Ptr = nullptr;
}
my_unique_ptr& operator=(my_unique_ptr&& _Y)
{
if (this == &_Y) return *this;
reset(_Y.release());
return *this;
}
_Dx& get_deleter()
{
return _myDeletor;
}
const _Dx& get_deleter() const
{
return _myDeletor;
}
_Ty& operator*() const
{
return *_Ptr;
}
pointer operator->() const
{
return &**this;
}
pointer get() const
{
return _Ptr;
}
operator bool() const
{
return _Ptr != nullptr;
}
pointer release()
{
_Ty* old = _Ptr;
_Ptr = nullptr;
return old;
}
void reset(pointer _P = nullptr)
{
pointer old = _Ptr;
_Ptr = _P;
if (old != nullptr)
{
_myDeletor(old);
}
}
void swap(my_unique_ptr _Y)
{
std::swap(_Ptr, _Y._Ptr);
std::swap(_myDeletor, _Y._myDeletor);
}
_Ty& operator[](size_t _Idx) const
{
return _Ptr[_Idx];
}
};
template<class _Ty,class ..._Type>
my_unique_ptr<_Ty> my_make_unique(_Type&& ... _arys)
{
return my_unique_ptr<_Ty>(new _Ty(_arys...));
}
#endif
my_unique_ptr的.cpp文件
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<list>
#include<type_traits>
#include<initializer_list>
#include<string>
#include<memory>
#include<stdio.h>
#include<map>
using namespace std;
#include"my_unique_ptr.h"
struct Logger
{
virtual void writeLog() = 0;
Logger() { cout << "日志记录器接口" << endl; }
virtual ~Logger() { cout << "~Logger: " << endl; }
};
class DatabaseLogger :public Logger
{
public:
DatabaseLogger() { cout << "DatabaseLogger::" << endl; }
~DatabaseLogger() { cout << "~DatabaseLogger" << endl; }
void writeLog()
{
cout << "数据库日志记录。" << endl;
}
};
class FileLogger :public Logger
{
public:
FileLogger() { cout << "FileLogger" << endl; }
~FileLogger() { cout << "~FileLogger" << endl; }
void writeLog() {
cout << "文件日志记录。" << endl;
}
};
struct LoggerFactory
{
virtual my_unique_ptr<Logger> createLogger() = 0;
LoggerFactory() { cout << "LoggerFactory" << endl; }
virtual ~LoggerFactory() { cout << "~LoggerFactory" << endl; }
};
class DatabaseLoggerFactory :public LoggerFactory
{
public:
DatabaseLoggerFactory() { cout << "DatabaseLoggerFactory " << endl; }
~DatabaseLoggerFactory() { cout << "~DatabaseLoggerFactory " << endl; }
my_unique_ptr<Logger> createLogger()
{
return my_unique_ptr<Logger>(new DatabaseLogger());
}
};
class FileLoggerFactory :public LoggerFactory
{
public:
FileLoggerFactory() { cout << "FileLoggerFactory" << endl; }
~FileLoggerFactory() { cout << "~FileLoggerFactory" << endl; }
my_unique_ptr<Logger> createLogger()
{
return my_unique_ptr<Logger>(new FileLogger());
}
};
int main()
{
my_unique_ptr<LoggerFactory> factory(new FileLoggerFactory());
my_unique_ptr<Logger> logger = factory->createLogger();
logger->writeLog();
factory = new DatabaseLoggerFactory();
logger = factory->createLogger();
logger->writeLog();
return 0;
}
|