C++ 为什么可以';t常数t*&;绑定到T*?

C++ 为什么可以';t常数t*&;绑定到T*?,c++,C++,VS2010显示错误C2440:'return':无法在下面的f3中从'char*'转换为'const char*&。当返回类型为const char*&时,为什么不能返回char* const char* const& f1() { static char* x = new char[5](); return x; } char* const& f2() { static char* x = new char[5](); return x; }

VS2010显示错误C2440:
'return':无法在下面的
f3
中从'char*'转换为'const char*&
。当返回类型为
const char*&
时,为什么不能返回
char*

const char* const& f1()
{
    static char* x = new char[5]();
    return x;
}

char* const& f2()
{
    static char* x = new char[5]();
    return x;
}

const char* & f3()
{
    static char* x = new char[5]();
    return x;    // error C2440
}

char* & f4()
{
    static char* x = new char[5]();
    return x;
}

出于同样的原因,您不能从
char**
强制转换为
const char**
。否则你可以写

f3() = "hello";

随后对f3的调用将能够写入字符串文本的内存,该字符串文本别名为C++11标准第8.5.3/2段中的静态本地
x

初始化后,无法将引用更改为引用另一个对象。请注意 引用的处理方式与它的赋值方式非常不同。参数传递(5.2.2)和函数值 返回(6.6.3)是初始化

这基本上告诉您,从函数返回值等同于执行初始化。因此,函数
f3()
无法编译,原因与下面代码段中的最后一次初始化无法编译相同:

char c = 'a';
char* x = &c;
const char*& y = x; // ERROR!
y
引用的对象的类型是
const char*
,而我们试图初始化它的表达式的类型(即
x
的类型)是
char*
。这些是不同的类型,当绑定引用时,初始化表达式的类型和初始化引用引用的对象的类型必须相同(基类和派生类除外,此处不涉及),除了顶级cv限定之外

这里,
const char*
中的
const
限定不是顶级限定,因为它适用于指向的对象,而不是指针本身:虽然指向的
char
值不能通过
const char*
指针修改,但指针本身可以重新分配

在标准术语中,这意味着类型
const char*
char*
与引用无关:

给定类型“
cv1t1
”和“
cv2t2
”,“
cv1t1
”是与“
cv2t2
”相关的引用,如果
T1
是与
T2
相同的类型,或者
T1
T2
的基类。如果
T1
参考与
T2
相关,且
cv1
cv2
相同,或大于
cv2
,则“cv1 T1”与“
cv2 T2
兼容。[……]

另一方面,函数
f2()

char c = 'a';
char* x = &c;
char* const& y = x; // OK
这里,被引用对象的类型是
char*const
,它(与
const char*
不同)在上面引用的段落*定义的意义上与
char*
兼容(在这种情况下,
const
限定是顶级限定)

特别是,根据8.5.3/5:

对“cv1 T1”类型的引用由“cv2 T2”类型的表达式初始化,如下所示:

-如果引用是左值引用和初始值设定项表达式

  • 是左值(但不是位字段),且“cv1 T1”与“cv2 T2”的引用兼容,
[……]

省略的部分与本案无关。这里,
char*const
char*
是引用兼容的,初始化是合法的(并且
f2()
编译)。另一方面,
const char*
char*
与引用不兼容,初始化是非法的(并且
f3()
不编译)

还打印“Hello undefined behavior”

“但是”,有人可能会说,“你把
char*&
变成了
const char*&
,而不是
char*
变成了
const char*&

很好:

void problem3( const char*& left, const char* right ) { left = right; }
const char*& problem4( char x = 0 ) {
  static char* bob = nullptr;
  if (bob && x)
    bob[0] = x;
  return const_cast<const char*&>(bob);
}
#include <iostream>
int main() {
  char const* buff = "hello problem";
  problem3( problem4(), buff );
  problem4('H');
  std::cout << buff << "\n";
}
void问题3(常量字符*&left,常量字符*right){left=right;}
常量字符*&问题4(字符x=0){
静态字符*bob=nullptr;
if(bob&&x)
bob[0]=x;
返回常量(bob);
}
#包括
int main(){
char const*buff=“你好问题”;
问题3(问题4(),buff);
问题4(“H”);

std::cout-Hmm,为什么f3()=“hello”;compile?f3()是常量,或者?它在常量int&i=b;?
f3()=“hello”的声明中计数“
编译是因为您的特定编译器允许您出于遗留原因执行一些愚蠢的操作。许多C API都有
char*
接口,它们承诺不会写入这些接口。因此,通过让字符串文本在静默状态下变为
char*
s,C API仍然可以工作。“顶级”是什么?”cv-资格?在这种情况下,你如何描述术语“顶级”的特征?@user1042389:我将尝试一个例子:在
int-const
int*const
中,
const
是顶级的;在
int-const*
中(与
const-int*
相同)“代码> const 不是顶层,因为它适用于指向<代码> int <代码>,而不是指针本身。一般来说,C++中可以用构造函数(例如指针)、“引用”、“数组”等构造复合类型。您的类型具有层次结构(在本例中是一个链)。顶级限定符是应用于此结构的顶级节点的限定符
// the "legal" way to do what the OP wants to do, but it leads to undefined
// behavior:
const char*& problem2( char*& c ) { return const_cast<const char*&>(c); }
void problem3( const char*& left, const char* right ) { left = right; }

#include <iostream>
int main() {
  char* c = nullptr;
  char const* buff = "hello undefined behavior";
  problem3( problem2(c), buff );
  c[0] = 'H';
  std::cout << buff << "\n";
}
void problem3( const char*& left, const char* right ) { left = right; }
const char*& problem4( char x = 0 ) {
  static char* bob = nullptr;
  if (bob && x)
    bob[0] = x;
  return const_cast<const char*&>(bob);
}
#include <iostream>
int main() {
  char const* buff = "hello problem";
  problem3( problem4(), buff );
  problem4('H');
  std::cout << buff << "\n";
}