获取 RVO 优化静态的地址

Taking address of RVO-optimized static

提问人:glades 提问时间:5/31/2023 更新时间:5/31/2023 访问量:53

问:

在下面的代码中,我尝试将一个单例实例注册到一个保留所有单例的全局数组中(在生产代码中,我可以根据模板参数实例化不同的单例,所以不用担心这个悖论:))。我想知道的是,我是否可以以某种方式获得 lambda 的 to-be 返回类型的地址,无论如何都应该对返回值进行优化,这样我就可以将其注册到全局条目数组中。

这是我得到的:

演示

#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;
}

输出:

my a = 15
my a from array = 0

至少它不是这样工作的,因为从数组中收集的条目仍然是 0。我该如何解决这个问题?

进一步说明

  • 我不能在此代码部分中使用动态内存分配!
C++ 单例 静态变量 返回值优化

评论

0赞 apple apple 5/31/2023
静态没有 RVO,如果它是在本地范围内创建的,它怎么可能是静态的?
1赞 Pepijn Kramer 5/31/2023
备注:我希望你的意思是还是你还想要副本?auto get_instance()auto& get_instance()
0赞 glades 6/1/2023
@PepijnKramer 哎呀!
1赞 Pepijn Kramer 6/1/2023
它发生在:) 也应该是(从 MyStruct 中删除复制构造函数也会显示这些错误)[[maybe_unused]] auto instance = get_instance();[[maybe_unused]] auto& instance = get_instance();
0赞 glades 6/1/2023
@appleappk 这真的重要吗?我认为 RVO 是“从一开始就在调用者给出的地址处构造返回对象”。在这种情况下,该地址将是静态的。如果我错了,请纠正我

答:

2赞 Artyer 5/31/2023 #1

NRVO 不是强制性的。但是你可以直接获取结果对象的地址:

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;
}

评论

0赞 glades 6/1/2023
哦,太棒了,我不知道你能做到!我什至不需要捕捉它......
0赞 glades 6/1/2023
我刚刚看到没有执行 RVO,这在我的情况下很糟糕,因为在我的情况下,MyStruct 是一个巨大的数组,它被分配在堆栈上并导致堆栈溢出。有没有办法直接构造到静态?