Eliminating instantiation of useless destructor calls?

时间秒杀一切 提交于 2021-02-19 04:06:08

问题


Well, my colleague is pretty in depth nitpicking about eliminating unnecessarily code instantiations for destructor functions. Still same situation, as mentioned in this question:

  • Very limited space for .text section (less 256 KB)
  • Code base should scale among several targets, including the most limited ones
  • Well known use cases of the code base by means some destructor logic is neccesary to manage object lifetimes or not (for many cases life-time of objects is infinite, unless the hardware is reset)

We have a target, that's very limited by means of .text section space available.
Unfortunately the GCC compiler will apparently instantiate code for even non virtual destructors, that actually have no side effects.

To get rid of these instantiatons he came up with the following wrapper construct, to eliminate the useless destructor calls:

The wrapper class:

#include <iostream>
#include <cstdint>
#include <utility>

template <typename T>
struct noop_destructor {
public:
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;

    template<typename... Args>
    noop_destructor(Args&&... args) {
        new (reinterpret_cast<void*>(wrapped_data)) T(std::forward<Args>(args)...);
    }

    explicit noop_destructor(const noop_destructor& rhs) {
        std::copy(rhs.wrapped_data,rhs.wrapped_data+sizeof(T),wrapped_data);
    }

    noop_destructor& operator=(const noop_destructor& rhs) {
        std::copy(rhs.wrapped_data,rhs.wrapped_data+sizeof(T),wrapped_data);
        return *this;
    }

    pointer operator->() {
        return reinterpret_cast<pointer>(wrapped_data);
    }
    const_pointer operator->() const {
        return reinterpret_cast<const_pointer>(wrapped_data);
    }
    reference operator*() {
        return *reinterpret_cast<pointer>(wrapped_data);
    }
    const_reference operator*() const {
        return *reinterpret_cast<const_pointer>(wrapped_data);
    }
private:
    uint8_t wrapped_data[sizeof(T)] __attribute__ ((aligned (__BIGGEST_ALIGNMENT__)));
};

A wrapped class (just ignore the side effect of calling std::cout << ... in the destructor, the real life classes in question to be wrapped, have just empty, non virtual destructors)

class A {
public:
    A() : x_() {}
    A(int x) : x_(x) {}
    ~A() {
        std::cout << "noop destructor call of class A" << std::endl;
    }
    void foo() {
        std::cout << "x_ = " << x_ << std::endl;
    }

private:
    int x_;
};

Some instantiations to demonstrate behavior:

int main() {
    A a1(5);
    noop_destructor<A> a2;

    a1.foo();
    (*a2).foo();
    return 0;
}

The approach just works fine (as you can see from the above code sample).

What I actually don't like about it, is you have no proof if a class actually can be wrapped with noop_destructor<>, and there's no indicator if T's destructor is actually empty, and can be safely eliminated or not.

Does anyone have an idea, how to make this more safe from a semantical level?

来源:https://stackoverflow.com/questions/28909598/eliminating-instantiation-of-useless-destructor-calls

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!