为什么使用条件运算符?:导致返回本地临时对象?

Why does using conditional operator ? : causes returning local temporary object?

提问人:Tony J 提问时间:10/20/2023 更新时间:10/20/2023 访问量:114

问:

我遇到了一个问题,即使用条件运算符在 MSVC 中返回垃圾string_view,因为string_view是由临时对象支持的?。

#include <string>
#include <iostream>

std::string hello("Hello");
char world[6] = { "World" };

std::string_view ChooseString( bool first )
{
    // warning: returning address of local temporary object
    return first ? hello : world; // returned string_view is garbage
    
    // all other ways of returning string_view works fine
    /*if ( first )
        return hello;
    else
        return world;*/
    //return first ? std::string_view( hello ) : std::string_view( world );
    //return hello;
    //return world;
}

int main()
{
    std::cout << ChooseString(true) << std::endl;
    std::cout << ChooseString(false) << std::endl;
}

然后我在 goldbot 上尝试了 clang 和 gcc,它们有相同的行为,其中 clang 发出警告:返回本地临时对象的地址。另外,只是返回你好或世界也很好。有人可以解释为什么第一种方式返回临时对象吗?

是因为在计算条件运算符后构造了字符串对象吗?

C++ 编译器警告

评论

0赞 user229044 10/20/2023
猜一猜:两个参数都必须转换为相同的类型,并且第一个参数决定了类型。您正在生成一个临时的 for 并将 a 返回到其中。?std::stringworldstring_view
4赞 user229044 10/20/2023
因为 的类型是由 和 的类型决定的,而不是由计算表达式后使用表达式的方式决定的。first ? hello : worldhelloworld
1赞 Peter 10/20/2023
三元运算符要求两个可能的结果具有相同的类型。如果一种类型可转换为另一种类型,则执行隐式转换。在您的例子中,是 的类型,并且是 的数组,因此转换为 (临时),三元运算符生成 ,然后转换为 .您要么需要阻止该转换(例如,在您的注释/代码中),要么避免创建临时转换(例如,通过将两个字符串显式转换为 )。hellostd::stringworldcharfirst ? hello : worldworldstd::stringstd::stringstd::string_viewifelsestd::string_view
5赞 Peter 10/20/2023
更一般地说,由涉及运算符的 ANY 表达式生成的类型由其操作数确定。它不是由随后如何使用该表达式的结果决定的。
3赞 Pete Becker 10/20/2023
@Peter — 在一种情况下,表达式的类型取决于它的使用方式:当您获取重载函数的地址时,表达式的类型(因此所选函数的版本)由它的使用方式决定。

答:

7赞 songyuanyao 10/20/2023 #1

是的,条件运算符的返回类型是操作数的常见类型。给定 ,即操作数的类型是 和 ,公共类型将是 。需要构造一个临时,然后使用临时来构造稍后返回的。first ? hello : world;std::stringconst char[]std::stringstd::stringworldstd::string_view

另一方面,对于返回类型是 ,并且所有 s 都是由 和 直接构造的,那么没有如上所述的问题。first ? std::string_view( hello ) : std::string_view( world )std::string_viewstd::string_viewhelloworld

评论

0赞 Tony J 10/20/2023
我也会从真中得到垃圾,这是否意味着也创建了临时副本?为什么编译器不推断为通用类型?hellofirsthellostring_view
0赞 songyuanyao 10/20/2023
@TonyJ,我想作为实现,总会返回一个,要么从 或 .std::stringhelloworld
2赞 user229044 10/20/2023
@TonyJ 编译器不会这样做,因为这不是C++。表达式的使用方式永远不会决定表达式的类型。结果就是结果,在生成后会转换为其他类型,但结果的使用方式不会影响表达式的计算方式。如果可行,您可以仅根据函数的返回类型重载函数;你不能,因为这不是 C++ 的工作方式。
1赞 songyuanyao 10/20/2023
@TonyJ关于返回类型,编译器找到的可以转换为然后被推导为通用类型。它不会进一步检查。有关详细信息,请参阅此处const char[]std::stringstd::string
1赞 Pete Becker 10/20/2023
@user229044——永远不要说永远。当您获取重载函数的地址时,它会因使用方式而消除歧义。之后,例如,选择第一个,然后选择第二个。也就是说,表达式的类型由强制转换决定。叹息。是的,这会分散注意力。void f(); void f(int)(void(*)())f(void(*)(int))ff