Лучший способ уничтожить объекты Global & Stati c? - PullRequest
0 голосов
/ 13 марта 2020

Каков наилучший способ завершить время жизни объекта со значением c длительности хранения?

Текущая реализация находит вызывающего __run_exit_handlers, который затем будет использоваться для определения __exit_funcs.

Однако это легко может произойти, поскольку смещение на __run_exit_handlers может легко измениться даже в glib c с той же версией. Другая вещь, которую можно сделать, это сначала разрешить адрес __run_exit_handlers, а затем использовать его при поиске вызывающего абонента, а не использовать жестко закодированное смещение вызова.

Текущий рабочий код :

#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

Ответы [ 2 ]

0 голосов
/ 13 марта 2020

Необходимость возиться с поведением по умолчанию продолжительности жизни таким образом указывает на то, что в вашем приложении имеется недостаток дизайна.

Так что вам следует либо подумать о реструктуризации вашей программы, чтобы не использовать глобальные переменные. Или, по крайней мере, изменить способ обращения с глобалами. Так что если вам действительно нужны глобальные переменные и их освобождение ранее, переключитесь на 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");

auto& getA()
{
    static auto a = std::make_unique<A>("getA");
    return a;
}

auto& getA2()
{
    static auto a = std::make_unique<A>("getA2");
    return a;
}

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

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

    getA();
    getA2();

    getA() = nullptr;

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

Таким образом, вы можете освободить объекты, управляемые unique_ptr ранее, но они будут освобождены при выходе автоматически если вы не установите их на nullptr вручную.

0 голосов
/ 13 марта 2020

Stati c объекты будут уничтожены при завершении программы.

Если вы хотите управлять ресурсами, не устанавливайте его как stati c или используйте указатель stati c. Здесь вы можете выделить и отменить выделение соответствующих ресурсов. Этот подход очень близок к одноэлементному, который считается антишаблоном .

Вывод: если вам нужно управлять ресурсом, не устанавливайте его c.

...