销毁全局和静态对象的最佳方法?

问题描述 投票:0回答:2

用静态存储持续时间结束对象生命周期的最佳方法是什么?

当前实现找到__run_exit_handlers的调用者,然后将其用于确定__exit_funcs

但是这很容易失败,因为即使在具有相同版本的glibc中,对__run_exit_handlers的偏移也可以轻松更改。可以做的另一件事是首先解析__run_exit_handlers的地址,然后将其用于查找呼叫者,而不是使用硬编码的呼叫偏移。

Current Working Code

#include <iostream>
#include <fstream>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <cstdio>

#include <execinfo.h>

struct A
{
    A(std::string pName)
        : mName(pName)
    {
        std::printf("%s %s\n", __PRETTY_FUNCTION__, mName.c_str());
    }

    ~A()
    {
        std::printf("%s %s\n", __PRETTY_FUNCTION__, mName.c_str());
    }
    volatile int i = 0;
    std::string mName;
};

A a{"a"};
A b{"b"};
A c{"c"};

class StaticDestroyer
{
public:
    StaticDestroyer()
    {
        std::ifstream maps("/proc/self/maps", std::ios::in);
        char line[1024];
        uint8_t* magic = nullptr;
        while (maps.getline(line, sizeof(line)))
        {
            char perms[4];
            uint8_t *magicbegin, *magicend;
            std::string lsv(line);
            if (std::string::npos == lsv.find("/libc-",0,6)) continue;
            std::sscanf(line, "%lx-%lx %4s", &magicbegin, &magicend, perms);
            if (perms[0]==114 && perms[2]==120)
            {
                 magic = findMagic(magicbegin, magicend);
                 break;
            }
        }

        if (magic==nullptr)
            throw std::runtime_error("magic not found!");

        mHead = *(HakaishinNode**)magic;
    }

    bool destroy(void* pTarget)
    {
        HakaishinNode *current = mHead;
        while (nullptr != current)
        {
            for (size_t i = current->idx-1 ; i>0; i--)
            {
                const  Hakaishin *const f = &current->fns[i];
                if (4 == f->type && pTarget == f->arg)
                {
                    void (*destruct) (void *arg, int status) = f->fn;
                    asm ("ror $2*8+1, %0\nxor %%fs:%c2, %0" : "=r" (destruct) : "0" (destruct), "i" (48));
                    destruct (f->arg, 1);
                    if (current->idx-1 != i) for (size_t j = i; j < current->idx ; j++) current->fns[j] = current->fns[j+1];
                    current->idx--;
                    return true;
                }
            }

            current = current->next;
        }
        return false;
    }
private:
    struct Hakaishin
    {
        long int type;
        void (*fn) (void *arg, int status);
        void *arg;
        void *dso_handle;
    };

    struct HakaishinNode
    {
        struct HakaishinNode *next;
        size_t idx;
        Hakaishin fns[32];
    };

    uint8_t* findMagic(uint8_t* magicbegin, uint8_t* magicend)
    {
        const void* const begin = magicbegin;
        int32_t ptr;
        while ((magicbegin+7) <= magicend)
        {
            if (magicbegin[0]==0x48 && (magicbegin[1]==0x8b || magicbegin[1]==0x8d))
            {
                std::memcpy(&ptr, magicbegin+3, sizeof(ptr));
                uint8_t* magicp = magicbegin+ptr+7;
                if (ptr==0x38a5c1) return magicp;
            }
            magicbegin++;
        }
        return nullptr;
    }

    HakaishinNode* mHead = nullptr;
};

A& getA()
{
    static A a{"getA"};
    return a;
}

A& getA2()
{
    static A a{"getA2"};
    return a;
}

int main()
{
    std::printf("entering...\n");
    StaticDestroyer d;
    d.destroy(&a);
    d.destroy(&b);
    auto& ga = getA();
    d.destroy(&ga);
    getA2();
    std::printf("returning...\n");
}

输出:

A::A(std::string) a
A::A(std::string) b
A::A(std::string) c
entering...
A::~A() a
A::~A() b
A::A(std::string) getA
A::~A() getA
A::A(std::string) getA2
returning...
A::~A() getA2
A::~A() c
c++ static global glibc
2个回答
0
投票

静态对象将在程序终止时被破坏。

如果您想管理资源,请不要将其设为静态或使用静态指针。在这里您可以分配和取消分配相应的资源。这种方法非常接近单例,被认为是anti pattern

结论:如果您需要管理资源,请不要将其设为静态。


0
投票

需要以这种方式来改变生命周期的默认行为,这表明您的应用程序中存在设计缺陷。

因此,您应该考虑重组程序以不使用全局变量。或至少更改全局变量的用法。或者,如果您确实需要全局变量并提前发布它们,则切换到unique_ptr

#include <iostream>
#include <functional>
#include <memory>
struct A
{
    A(std::string pName)
        : mName(pName)
    {
        std::printf("%s %s\n", __PRETTY_FUNCTION__, mName.c_str());
    }

    ~A()
    {
        std::printf("%s %s\n", __PRETTY_FUNCTION__, mName.c_str());
    }
    volatile int i = 0;
    std::string mName;
};

auto a = std::make_unique<A>("a");
auto b = std::make_unique<A>("b");
auto c = std::make_unique<A>("c");


int main() {
    std::printf("entering...\n");

    a = nullptr;
    b = nullptr;
    c = nullptr;

    std::printf("returning...\n");
}

这样,您可以释放之前由unique_ptr管理的对象,但是如果您不将它们手动设置为nullptr,它们将在退出时自动释放。

© www.soinside.com 2019 - 2024. All rights reserved.