引用的条件赋值 可以理解我的C++标准吗?请详细说明一下?
这是我的示例程序引用的条件赋值 可以理解我的C++标准吗?请详细说明一下?,c++,gcc,C++,Gcc,这是我的示例程序 #include <string> #include <iostream> int main(int argc, char* argv[]) { const std::string message("hello world"); std::cout << std::hex << (void*)message.c_str() << std::endl; const std::string&
#include <string>
#include <iostream>
int main(int argc, char* argv[]) {
const std::string message("hello world");
std::cout << std::hex << (void*)message.c_str() << std::endl;
const std::string& toPrint = (argc > 0) ? message : "";
std::cout << std::hex << (void*)toPrint.c_str() << std::endl;
return 0;
}
message
和toPrint
似乎引用了与我预期相同的实例。但是,在另一台机器上,会发生以下情况:
# g++ --version && g++ str_test.cpp && ./a.out
g++ (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
0x7ffeb9ab4ac0
0x7ffeb9ab4ae0
在这里,编译器似乎为toPrint
构建了一个指向的message
副本
根据C++标准,什么行为是正确的?或者它通常是未定义的?您被GLIBCs写时复制字符串共享弄糊涂了。将测试程序更改为:
#include <string>
#include <iostream>
int main(int argc, char* argv[]) {
const std::string message("hello world");
std::cout << std::hex << (void*)&message << std::endl;
const std::string& toPrint = (argc > 0) ? message : "";
std::cout << std::hex << (void*)&toPrint << std::endl;
return 0;
}
#包括
#包括
int main(int argc,char*argv[]){
const std::字符串消息(“hello world”);
Martin Bonner解释了为什么即使是字符串的副本,地址也可以相同
为了解释,为什么消息和toPrint似乎引用了与我预期相同的实例。
被误导了,我将引用标准
让我们首先探讨需要什么转换(我想这不是这里的问题,只是为了完整性)。否则忽略第一个。它指的是void
类型表达式的情况
[expr.cond]/3否则,如果第二个和第三个操作数具有不同的类型,并且其中一个具有(可能是cv限定的)类类型,或者如果两者都是相同值类别和相同类型(cv限定除外)的glvalues,则尝试将这些操作数中的每一个转换为另一个的类型。确定类型为T1
的操作数表达式E1
是否可以转换为与操作数表达式E2匹配的过程e> 类型T2
定义如下:
- 如果
E2
是一个左值:E1
可以转换为匹配E2
如果E1
可以隐式转换为类型“levalue reference toT2
”,但在转换过程中引用必须直接绑定到左值。(无法将类型为std::string
的左值引用绑定到strig文本)
- 如果
E2
是一个xvalue:E1
可以转换为匹配E2
如果E1
可以隐式转换为类型“rvalue reference toT2
”,但必须受引用必须直接绑定的约束。(此处无xvalue)
- 如果
E2
是一个右值,或者如果上述两种转换都无法完成,并且至少有一个操作数具有(可能是cv限定的)类类型:
- 如果
E1
和E2
具有类别类型,并且基础类别类型相同或一个是另一个的基类:E1
可以转换为匹配E2
,如果T2
的类别与T1
的类别相同或基类,并且T2
的cv限定为与T1
的cv限定相同或更大的cv限定。如果应用转换,E1
通过从E1
复制初始化类型为T2
的临时变量并将该临时变量用作转换的操作数,将E1
更改为类型为T2
的PR值。(字符串文字没有类类型)
- 否则(即,如果
E1
或E2
具有非类类型,或者如果它们都具有类类型,但基础类既不相同,也不是另一个的基类):E1
可以转换为匹配E2
如果E1
可以隐式转换为表达式E2
在E2
转换为prvalue时将具有的类型(或者如果E2
是prvalue,则其具有的类型)。(此项适用)
最后一个项目符号涵盖了这种情况。字符串文字具有非类类型,可以将其转换为匹配std::string
prvalue
现在,让我们探讨转换如何影响结果
4如果第二个和第三个操作数是相同值类别的glvalues,并且具有相同的类型(它们不是),则结果
属于该类型和值类别,如果第二个或第三个操作数是位字段,或者如果
两者都是位字段
5否则,结果为prvalue。如果第二个和第三个操作数的类型不同,并且其中一个操作数具有(可能是cv限定的)类类型,则使用重载解析来确定要应用于操作数的转换(如果有)(13.3.1.2,13.6)。如果重载解析失败,则程序格式错误。否则,将应用由此确定的转换,并在本节的其余部分使用转换后的操作数代替原始操作数
所以,结果是prvalue!它不是左值引用。如何从左值中获取prvalue
6对第二个和第三个操作数执行左值到右值(4.1)、数组到指针(4.2)和函数到指针(4.3)的标准转换。在这些转换之后,下列之一应保持不变:
- 第二个和第三个操作数具有相同的类型;结果为该类型。如果操作数具有
类类型(它们在转换后执行),结果是结果类型的临时值,它是从
第二个操作数或第三个操作数,具体取决于第一个操作数的值
因此,我们知道结果将从操作数表达式进行复制初始化。尽管我们分配了一个引用,并且条件的操作数是对同一类型的左值引用,但该引用将绑定到从操作数复制的临时引用
如果您使用另一个对const std::string
的左值引用作为第三个操作数,那么您只需将
#include <string>
#include <iostream>
int main(int argc, char* argv[]) {
const std::string message("hello world");
std::cout << std::hex << (void*)&message << std::endl;
const std::string& toPrint = (argc > 0) ? message : "";
std::cout << std::hex << (void*)&toPrint << std::endl;
return 0;
}