在动态分配时将C++11对象添加到列表中
Adding C++11 object to list when dynamically allocated?
假设我有一个类X:
struct X
{
...
};
我有一个全局向量V:
vector<X*> V;
我想将X的新实例添加到V,当且仅当它是动态分配的(作为一个完整的派生对象,而不是子对象(:
int main()
{
X x; // not added to V
new X; // added to V
struct D : X {};
new D; // not added to V
}
有办法做到这一点吗?也许是通过某种方式重载/覆盖operator new
?
struct X {
public:
static void* operator new(std::size_t size) {
void* p = ::operator new(size);
if (size == sizeof(X))
V.push_back(static_cast<X*>(p));
}
static void operator delete(void* p, std::size_t size) {
if (size == sizeof(X))
V.erase(std::remove(V.begin(), V.end(), p), V.end());
::operator delete(p, size);
}
};
注意,有时V
的元素指向还不是或不再实际是X
的存储器。用户可以绕过这些功能,但他们必须尝试。
如果您有另一个继承X
但大小相同的类(因此除了"空"基类之外没有其他子对象(,如struct Y : public X {};
,则上面的代码会认为new Y
正在分配X
。如果这是一个问题,您还需要将operator new
和operator void
添加到每个此类Y
中。我认为没有比这更通用的解决方案了。
基于aschepler的方法构建,但现在使用虚拟基类重定向D
的构造函数调用(不向向量添加实例(。
主要思想是执行两步注册:首先,将对operator new
的任何调用(无论是针对X
还是派生类(注册到unordered_set
(X::dyn_alloc_set
(。然后,在构造X
时,根据最派生的类型进行选择,如果this
已被动态分配,则将其添加到V
;如果它不是派生类,则添加。
虚拟基类的构造函数必须从最派生的类型调用,因此在构造过程中可以使用它来区分D
和X
。
#include <unordered_set>
#include <typeinfo>
#include <vector>
#include <iostream>
#include <algorithm>
struct X;
std::vector<X*> V;
struct virt_base_class
{
friend struct X;
private:
virt_base_class(X* p); // this can only and will only be called by X
public:
virt_base_class() // this will be called by any class derived from X
{}
};
struct X
: protected virtual virt_base_class
{
private:
friend class virt_base_class;
static std::unordered_set<X*> dyn_alloc_set;
static bool dynamically_allocated(X* p)
{
return dyn_alloc_set.count(p) > 0;
}
public:
X()
: virt_base_class(this)
{}
static void* operator new(std::size_t size) {
void* p = ::operator new(size);
if (size == sizeof(X))
dyn_alloc_set.insert( static_cast<X*>(p) );
return p;
}
static void operator delete(void* p, std::size_t size) {
if (size == sizeof(X))
{
dyn_alloc_set.erase( static_cast<X*>(p) );
V.erase( std::remove(V.begin(), V.end(), static_cast<X*>(p)),
V.end() );
}
::operator delete(p);
}
};
virt_base_class::virt_base_class(X* p)
{
if( X::dynamically_allocated(p) )
V.push_back(p);
}
struct D : X
{}; // D::D will implicitly call virt_base_class::virt_base_class()
std::unordered_set<X*> X::dyn_alloc_set;
int main()
{
X x;
X* p = new X;
D d;
D* pd = new D;
std::cout << V.size();
}
更新:使用thread_local
存储以避免unordered_set
:
struct X
: protected virtual virt_base_class
{
private:
friend class virt_base_class;
static thread_local X* last_dyn_allocated;
static bool dynamically_allocated(X* p)
{
return p == last_dyn_allocated;
}
public:
X()
: virt_base_class(this)
{}
static void* operator new(std::size_t size) {
void* p = ::operator new(size);
if (size == sizeof(X))
{
last_dyn_allocated = static_cast<X*>(p);
}
return p;
}
static void operator delete(void* p, std::size_t size) {
if (size == sizeof(X))
{
X* pp = static_cast<X*>(p);
if(last_dyn_allocated == pp)
last_dyn_allocated = nullptr;
V.erase( std::remove(V.begin(), V.end(), pp),
V.end() );
}
::operator delete(p);
}
};
thread_local X* last_dyn_allocated = nullptr;
我认为最好的近似方法是强制使用动态分配对象的工厂:
#include <algorithm>
#include <utility>
#include <vector>
class X {
static std::vector<X*> dynamic_xs;
static void* operator new(std::size_t size) {
return ::operator new(size);
}
public:
~X() {
auto end = std::end(dynamic_xs);
auto pos = std::find(std::begin(dynamic_xs), end, this);
if (pos != end) {
if (pos != --end) {
std::iter_swap(pos, end - 1);
}
dynamic_xs.pop_back();
}
}
template <typename... Args>
friend X* make_x(Args&&... args) {
X* p = new X(std::forward<Args>(args)...);
dynamic_xs.push_back(p);
return p;
}
};
std::vector<X*> X::dynamic_xs;
客户端可以实例化堆栈分配的X
,但动态分配会导致访问错误,因为operator new
是private
。
相关文章:
- 如何在 sqlite3 中的表中添加整数列表
- 有什么方法可以将元素添加到列表中,如图所示?
- 测试驱动开发 c++:如何将对象添加到向量中,将歌曲添加到播放列表并对其进行测试
- 将新元素添加到列表中,并返回对该元素的引用?
- 可视化 如何将 CString 值列表添加到 MFC C++ 中的组合框中?
- 通过在带有 C++ 的列表中添加连续元素来计算新的整数列表
- CSUF EPP - 你有什么想法(在添加到链接列表末尾时遇到麻烦)
- 将集合的随机元素添加到列表中,然后将其从原始集合中移除
- 如何使用LLVM C++API向保留节点列表添加
- 是否可以使用OpenMP并行化一个列表,该列表可以在每次迭代中添加新元素
- 如何确保我的节点被添加到链接列表中
- 如何读取文件的内容,如果文件中的单词重复,请将它们添加到列表中?
- 在 MFC 组合框中设置文本,而不将其添加到列表中
- 在C++中,如何将参数添加到"Args&&... args"参数列表中?
- C++将静态多态类自添加到子类的 constexpr 列表中
- 添加气泡排序代码以排列列表
- 双链接列表添加元素不起作用,不知何故它总是保持为空
- 如何从列表中将对象添加到图表中?
- 在运行时添加列表和从列表中删除
- MFC应用程序在添加列表控件元素时卡住