godlikepanos / anki-3d-engine

AnKi 3D Engine - Vulkan backend, modern renderer, scripting, physics and more

Home Page:http://www.anki3d.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Improve exception safety with smart pointers

elfring opened this issue · comments

Would you like to wrap any pointers with the class template “std::unique_ptr”?

Hi and thanks for the question,

First of all I'd like to mention that AnKi doesn't use exceptions so it might be less useful to have RAII (because that's what we are talking about right?).

RAII has some annoying characteristics that don't sit well with some systems of AnKi. With RAII the order of the members in classes matters. In some cases though the order is based on optimal packing or for better cache behavior. Having unique_ptrs in those cases is doable but it defeats the purpose.

The most annoying thing though is that AnKi has custom allocators for everything (in retrospect this was probably a bad idea). That means that every typename wrapped in a unique_ptr should know the allocator that will be used to deallocate the pointer. This creates a problem because it forces the allocator to be part of the unique_ptr. That will create bigger structures and will impact caching performance.

The TL;DR version is that yes I should (and can) use more of unique_ptrs but not in all cases.

… AnKi doesn't use exceptions …

I would find it nice if a corresponding software build parameter can be reconsidered.

With RAII the order of the members in classes matters.

The order of involved items should usually matter, shouldn't it?

This creates a problem because it forces the allocator to be part of the unique_ptr.

The smart pointer should perform the desired cleanup function as usual.

I would find it nice if a corresponding software build parameter can be reconsidered.

I'm not sure I understand the usefulness of having exceptions enabled. AnKi is designed to not use exceptions. Leaving them on serves no purpose I would guess. What am I missing?

The order of involved items should usually matter, shouldn't it?

I think I explained myself poorly. Imagine I have this class:

class Foo
{
    unique_ptr<Boo> m_ptr0;
    Other m_other;
    unique_ptr<Hoo> m_ptr1;
};

The order of m_ptr0, m_other, m_ptr1 defines the initialization order and as a result the destruction order in ~Foo() as well as the placement of the members in memory. But what if I want to have this:

class Foo
{
    // Cacheline 1: Frequently used
    unique_ptr<Hoo> m_ptr1;
    Other m_other;

    // Cacheline 2: Rarely used
    unique_ptr<Boo> m_ptr0;
};

In this case I want to to have a different order to maximize the cache throughput. This breaks the initialization order.

In the 2nd case the RAII gets in the way.

The smart pointer should perform the desired cleanup function as usual.

Also explained myself poorly. Let me explain.

The unique_ptr will use either a default deleter or a custom one. Since AnKi is using custom allocators it should be the later. Since AnKi's allocators are not empty objects (as opposed to STL's default deleter) this means that AnKi's unique_ptr will be sizeof(void*)+sizeof(allocator). Doing that for every pointer is wasteful and bad for caching.

Does this make sense?

I'm not sure I understand the usefulness of having exceptions enabled.

I imagine that software users would occasionally like to catch C++ exceptions instead of an immediate program termination as an error response because of a software build parameter like “-fno-exceptions”.

In the 2nd case the RAII gets in the way.

I have got understanding difficulties for this view.

  • Will the member variables fit still into cache lines as desired despite of smart pointer usage?
  • How often does the initialisation order not fit to your caching concerns?

Since AnKi's allocators are not empty objects …

Costumised cleanup functions can trigger specific run time consequences.

Can smart pointers be applied easier for any local variables?

Closing this ticket since it's a big refactoring and it's difficult to be done with the current design