具有本地缓冲区优化的智能指针
Smart pointer with local buffer optimization
这是启用类型擦除删除器和本地缓冲区优化的智能指针示例。出自书本https://books.google.am/books/about/Hands_On_Design_Patterns_with_C++.html?id=iQGGDwAAQBAJ&printsec=frontcover&source=kp_read_button&redir_esc=y#v=onepage&q&f=false
#include <iostream>
template <typename T>
class smart_ptr
{
struct deleter_base
{
virtual ~deleter_base() {};
virtual void apply(T* p) = 0;
};
template <typename Deleter>
struct deleter : public deleter_base
{
deleter(Deleter d): m_d(d) {}
void apply(T* p) override
{
m_d(p);
}
Deleter m_d;
};
deleter_base* m_db;
T* m_p;
char m_buf[16];
public:
template <typename Deleter>
smart_ptr(T* p, Deleter d)
: m_p(p)
, m_db( sizeof(Deleter) > sizeof(m_buf) ? new deleter<Deleter>(d) : new (m_buf) deleter<Deleter>(d))
{
}
~smart_ptr()
{
m_db->apply(m_p);
if (static_cast<void*>(m_db) == static_cast<void*>(m_buf))
{
m_db->~deleter_base();
}
else
{
delete m_db;
}
}
T& operator*() {return *m_p;}
const T& operator*() const {return *m_p;}
T* operator->() { return m_p; }
const T* operator->() const { return m_p; }
};
struct Test
{
Test(double d): m_d(d) { std::cout << "Test::Test" << std::endl; }
~Test() { std::cout << "Test::~Test" << std::endl; }
double m_d;
};
int main()
{
auto deleter = [](Test * t) {delete t;};
smart_ptr<Test> spd(new Test(3.6), deleter);
std::cout << spd->m_d << std::endl;
}
一个问题。当删除器不适合本地缓冲区时,我们为它分配内存并保持 m_buf
未初始化。是错误还是我遗漏了什么?
在析构函数中,我们将具有随机值的 m_buf
与 new deleter<Deleter>(d)
返回的值进行比较。这些值匹配并非不可能,对吧?
这不是错误 - 内存未初始化是有效的。当您从未初始化的内存中读取时,您只有未定义的行为 (UB)。
这是有道理的——如果仅仅拥有未初始化的内存就已经是一个错误,那么在上面的 smart_ptr
ctor 中放置新的内容将毫无意义。但这是安全的,因为它以写入开始。
这是启用类型擦除删除器和本地缓冲区优化的智能指针示例。出自书本https://books.google.am/books/about/Hands_On_Design_Patterns_with_C++.html?id=iQGGDwAAQBAJ&printsec=frontcover&source=kp_read_button&redir_esc=y#v=onepage&q&f=false
#include <iostream>
template <typename T>
class smart_ptr
{
struct deleter_base
{
virtual ~deleter_base() {};
virtual void apply(T* p) = 0;
};
template <typename Deleter>
struct deleter : public deleter_base
{
deleter(Deleter d): m_d(d) {}
void apply(T* p) override
{
m_d(p);
}
Deleter m_d;
};
deleter_base* m_db;
T* m_p;
char m_buf[16];
public:
template <typename Deleter>
smart_ptr(T* p, Deleter d)
: m_p(p)
, m_db( sizeof(Deleter) > sizeof(m_buf) ? new deleter<Deleter>(d) : new (m_buf) deleter<Deleter>(d))
{
}
~smart_ptr()
{
m_db->apply(m_p);
if (static_cast<void*>(m_db) == static_cast<void*>(m_buf))
{
m_db->~deleter_base();
}
else
{
delete m_db;
}
}
T& operator*() {return *m_p;}
const T& operator*() const {return *m_p;}
T* operator->() { return m_p; }
const T* operator->() const { return m_p; }
};
struct Test
{
Test(double d): m_d(d) { std::cout << "Test::Test" << std::endl; }
~Test() { std::cout << "Test::~Test" << std::endl; }
double m_d;
};
int main()
{
auto deleter = [](Test * t) {delete t;};
smart_ptr<Test> spd(new Test(3.6), deleter);
std::cout << spd->m_d << std::endl;
}
一个问题。当删除器不适合本地缓冲区时,我们为它分配内存并保持 m_buf
未初始化。是错误还是我遗漏了什么?
在析构函数中,我们将具有随机值的 m_buf
与 new deleter<Deleter>(d)
返回的值进行比较。这些值匹配并非不可能,对吧?
这不是错误 - 内存未初始化是有效的。当您从未初始化的内存中读取时,您只有未定义的行为 (UB)。
这是有道理的——如果仅仅拥有未初始化的内存就已经是一个错误,那么在上面的 smart_ptr
ctor 中放置新的内容将毫无意义。但这是安全的,因为它以写入开始。