【问题标题】:C++ nested designated initializer with pointer带有指针的 C++ 嵌套指定初始值设定项
【发布时间】:2021-06-19 20:23:34
【问题描述】:

我认为能够使用指定的初始化程序来初始化一个用指针引用另一个结构的结构会很有用。这种模式经常发生在某些 API(例如 Vulkan)中。例如,考虑以下结构:

struct A {
    int v;
};

struct B {
    int v;
    A* a;
};

struct C {
    B* b;
};

还有一个以C为参数的函数

void func(const C& c) {}

我想出了一种使用unmove() (ref) 函数将右值转换为左值的方法:

template <typename T>
T& unmove(T&& v) { return v; }

使用这个函数,嵌套初始化可以写成

func({
    .b = &unmove(B{
        .v = 1,
        .a = &unmove(A{
            .v = 2
        })
    })
});

我的问题:就标准而言,它是该功能的有效用法吗?还是我错过了什么?

【问题讨论】:

  • 那些临时对象存在直到 ; 然后所有指针都悬空 - 阅读您链接的完整答案,尤其是 "...如果函数返回一个引用,它比完整表达式的寿命更长,它变成了一个悬空引用......".
  • 这能回答你的问题吗? Rvalue to lvalue conversion?
  • 我认为在这种情况下,更大的考虑是其他程序员(或以后的你自己)想知道到底发生了什么——即使合法,也很难认可这一点

标签: c++ language-lawyer c++20


【解决方案1】:

只要函数不存储或返回引用的对象或其地址或嵌套指针以供以后使用,这是安全的。临时对象将在完整表达式的末尾被销毁,因此提到的存储/返回的引用/指针将无效。

[class.temporary]

... 临时对象作为评估完整表达式 ([intro.execution]) 的最后一步被销毁,该完整表达式 ([intro.execution]) (词法上)包含它们被创建的点。 ...

【讨论】:

    【解决方案2】:

    我会成功的 addressof_rvalue:

    template <typename T>
    T* addressof_rvalue(T&& v) { return std::addressof(v); }
    template <typename T>
    T* addressof_rvalue(T& v) = delete;
    

    它是安全的,只要指针不超过你正在调用的函数。

    func({
        .b = addressof_rvalue(B{
            .v = 1,
            .a = addressof_rvalue(A{
                .v = 2
            })
        })
    });
    

    【讨论】:

    • 这个名字有点混乱。我最初的解释是该函数“将指针转换为右值”。虽然,第二个虽然我可以看到返回的指针指向一个右值。
    猜你喜欢
    • 2020-07-20
    • 2019-09-27
    • 2020-01-13
    • 1970-01-01
    • 1970-01-01
    • 2016-05-15
    • 1970-01-01
    • 2020-01-13
    • 1970-01-01
    相关资源
    最近更新 更多