RAII - 存储"void*&"或"void**"
RAII - store `void*&` or `void**`
我正在设计一个包装器类来提供RAII功能。原始用例如下:
void* tid(NULL);
OpenFunc(&tid);
CloseFunc(&tid);
在我引入一个新的包装器类之后,我希望未来的用法如下:
void* tid(NULL);
TTTA(tid);
或
TTTB(tid);
问题:
TTTA
和TTTB
哪个实现更好?或者他们都不好,请介绍一个更好的。
我担心的一件事是,在资源分配后,id
将在TTTA
或TTTB
类之外访问,直到id
被破坏。根据我的理解,我的设计应该不会有副作用。
谢谢
class TTTA : boost::noncopyable
{
public:
explicit TTTA(void *id)
: m_id(id)
{
OpenFunc(&m_id); // third-party allocate resource API
}
~TTTA()
{
CloseFunc(&m_id); // third-party release resource API
}
private:
void* &m_id; // have to store the value in order to release in destructor
}
class TTTB : boost::noncopyable
{
public:
explicit TTTB(void *id)
: m_id(&id)
{
OpenFunc(m_id); // third-party allocate resource API
}
~TTTB()
{
CloseFunc(m_id); // third-party release resource API
}
private:
void** m_id; // have to store the value in order to release in destructor
}
//传入指针比较
class TTTD
{
public:
TTTD(int* id) // Take as reference, do not copy to stack.
: m_id(&id)
{
*m_id = new int(40);
}
private:
int** m_id;
};
class TTTC
{
public:
TTTC(int* &id)
: m_id(id)
{
m_id = new int(30);
}
private:
int* &m_id;
};
class TTTB
{
public:
TTTB(int* id)
: m_id(id)
{
m_id = new int(20);
}
private:
int* &m_id;
};
class TTTA
{
public:
TTTA(int** id)
: m_id(id)
{
*m_id = new int(10);
}
private:
int** m_id;
};
int main()
{
//////////////////////////////////////////////////////////////////////////
int *pA(NULL);
TTTA a(&pA);
cout << *pA << endl; // 10
//////////////////////////////////////////////////////////////////////////
int *pB(NULL);
TTTB b(pB);
//cout << *pB << endl; // wrong
//////////////////////////////////////////////////////////////////////////
int *pC(NULL);
TTTC c(pC);
cout << *pC << endl; // 30
//////////////////////////////////////////////////////////////////////////
int *pD(NULL);
TTTD d(pD);
cout << *pD << endl; // wrong
}
两者都是坏的。
TTTA存储对存储在堆栈上的变量(参数id)的引用。
TTTB存储一个指向存储在堆栈上的变量的指针。
这两次,当构造函数返回时,变量都超出了作用域。
编辑:既然你想要修改的值,最简单的修复是把指针作为引用;这将使TTTC引用实际指针,而不是将指针作为非引用形参时所做的本地复制;
class TTTC : boost::noncopyable
{
public:
explicit TTTA(void *&id) // Take as reference, do not copy to stack.
: m_id(id)
...
private:
void* &m_id; // have to store the value in order to release in destructor
}
破坏你的版本的简单测试是在类中添加一个print
方法来打印指针值并执行;
int main() {
void* a = (void*)0x200;
void* b = (void*)0x300;
{
TTTA ta(a);
TTTA tb(b);
ta.print();
tb.print();
}
}
TTTA和TTTB在我的机器上都将两个值打印为0x300。当然,结果真的是UB;
你为什么要做tid
呢?它将信息泄露给客户端,并使使用时间延长两倍(两行而不是一行):
class tttc {
void* id;
public:
tttc() {
OpenFunc(&id);
}
~tttc() {
CloseFunc(&id);
}
tttc(tttc const&) = delete;
tttc& operator =(tttc const&) = delete;
};
注意这个类禁止复制——你的解决方案违反了三个规则。
如果您需要从外部访问id
,则提供tttc
内部的转换:
void* get() const { return id; }
或者,如果绝对必要,通过隐式转换:
operator void*() const { return id; }
(但要谨慎使用,因为隐式转换削弱了类型系统,可能导致难以诊断的错误。)
然后在标准库中有std::unique_ptr
,它使用自定义删除器,实际上实现了相同的功能,并且正确地实现了三规则
完全包装呢?这样,您就不必担心管理两个变量的生命周期,而只需管理一个变量。
class TTTC
{
void* m_id;
public:
TTTC()
: m_id(nullptr)
{
OpenFunc(&m_id); // third-party allocate resource API
}
TTTC(TTTC const&) = delete; // or ensure copying does what you expect
void*const& tid() const { return m_id; }
~TTTC()
{
CloseFunc(&m_id); // third-party release resource API
}
};
使用它本身就是简单的:
TTTC wrapped;
DoSomethingWithTid(wrapped.tid());
相关文章:
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 将字符串存储在c++中的稳定内存中
- std::原子加载和存储都需要吗
- C++:将控制台输出存储在宏中更好吗
- 如何将 std::string 作为构造函数参数传递,并将其保存的 C 字符串存储在 void 指针中?
- 合法的方式将destructor信息存储到void*
- 在 void 指针中存储整数的往返安全性
- 如何在 c++ 结构中的 void* 变量中调用存储函数(回调)
- 从void Pointer(创建通用存储)铸造有什么问题
- void 函数 C++ 错误 此声明没有存储类或类型说明符
- 如何将 void 指针类型转换为 int 指针,然后在其中存储 int
- c++将存储在std::vector中的数据传递给c_func(void*data)
- 存储各种 void 函数指针的向量及其参数
- 可以在C++中用void指针存储类对象的地址
- C++中存储在void中的值是多少
- RAII - 存储"void*&"或"void**"
- 为Node.js插件在void *中检索和存储V8对象
- 我想存储函数的void指针以及它们的类型
- 将派生对象存储到void*中,然后从中抛出基对象是否不安全
- 如何在堆栈c++容器中存储void*