加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

动态分配时添加C 11对象列表?

发布时间:2020-12-16 03:16:04 所属栏目:百科 来源:网络整理
导读:假设我有一个类X: struct X{ ...}; 我有一个全局向量V: vectorX* V; 当且仅当动态分配(作为一个完整的大多数派生对象而不是一个子对象)时,我想向X添加一个X的新实例: int main(){ X x; // not added to V new X; // added to V struct D : X {}; new D; /
假设我有一个类X:
struct X
{
   ...
};

我有一个全局向量V:

vector<X*> V;

当且仅当动态分配(作为一个完整的大多数派生对象而不是一个子对象)时,我想向X添加一个X的新实例:

int main()
{
    X x; // not added to V
    new X; // added to V

    struct D : X {};
    new D; // not added to V
}

有没有办法这样做?也许是通过重载/覆盖运算符新的吗?

解决方法

基于 aschepler的方法,但现在使用虚拟基类来重定向D的构造函数调用(不向向量添加实例).

主要思想是进行两步注册:首先,将无效的new(无论是X或派生类)的任何调用注册到unordered_set(X :: dyn_alloc_set).然后,当构建X时,根据最多派生类型进行选择,如果已经被动态分配,则将其添加到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(),pp),V.end() );
        }
        ::operator delete(p);
    }
};

thread_local X* last_dyn_allocated = nullptr;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读