c++singletonstatic-variablesreturn-value-optimization

Taking address of RVO-optimized static


In the following code I try to register a singleton instance with a global array that keeps all singletons (in production code I can instantiate different singletons based on template parameters so don't worry about this paradox :) ). What I wanted to know is if I can somehow get the address of to-be return type of the lambda which is ought to be return value optimized anyway, so I can register it with the global entries array.

Here's what I've got:

Demo

#include <ranges>
#include <cstdio>
#include <cstdint>
#include <iostream>

namespace rng = std::ranges;

struct MyStruct {
    uint32_t a = 0;
};

struct AllStructs {
    std::array<MyStruct*, 10> items = { 0 };
    std::size_t count = 0;
} g_entries;

auto get_instance() {
    static MyStruct instance = []() -> MyStruct{
        MyStruct ret{ 15 };
        g_entries.items[g_entries.count++] = &ret;
        return ret;
    }();

    return instance;
}

int main() {
    [[maybe_unused]] auto instance = get_instance();

    std::cout << "my a = " << instance.a << std::endl;
    std::cout << "my a from array = " << g_entries.items[0]->a << std::endl;
}

Output:

my a = 15
my a from array = 0

It doesn't work like this at least, as the entry gleaned from the array is still 0. How can I work around this?

Further notes:


Solution

  • NRVO is not mandatory. But you can just take the address of the result object directly:

    auto& get_instance() {
        static MyStruct instance = []() -> MyStruct {
            MyStruct ret{ 15 };
            g_entries.items[g_entries.count++] = &instance;
            return ret;
        }();
    
        // Or if you don't otherwise need `ret`
        static MyStruct instance = []{
            g_entries.items[g_entries.count++] = &instance;
            return MyStruct{ 15 };
        }();
    
        return instance;
    }