C++ 引用类型转换运算符:自找麻烦?

C++ 引用类型转换运算符:自找麻烦?,c++,operators,reference,type-conversion,operator-keyword,C++,Operators,Reference,Type Conversion,Operator Keyword,当我使用g++ class A {}; void foo(A&) {} int main() { foo(A()); return 0; } 我收到以下错误消息: > g++ test.cpp -o test test.cpp: In function ‘int main()’: test.cpp:10: error: invalid initialization of non-const reference of type ‘A&’ from a

当我使用
g++

class A {};

void foo(A&) {}

int main()
{
  foo(A());
  return 0;
}
我收到以下错误消息:

> g++ test.cpp -o test     
test.cpp: In function ‘int main()’:
test.cpp:10: error: invalid initialization of non-const reference of type ‘A&’ from a temporary of type ‘A’
test.cpp:6: error: in passing argument 1 of ‘void foo(A&)’
经过深思熟虑,这些错误对我来说很有意义
A()
只是一个临时值,不是堆栈上的可分配位置,因此它似乎没有地址。如果它没有地址,那么我就不能引用它。好的,很好

但是等等!如果我将以下转换运算符添加到类
A

class A
{
public:
  operator A&() { return *this; }
};
那么一切都好了!我的问题是这是否有点安全。当
A()
被构造为临时值时,
这个
具体指向什么

这一事实给了我一些信心

void foo(const A&) {}

可以根据
g++
和我使用过的所有其他编译器接受临时值。
const
关键字总是可以丢弃的,因此如果
const a&
参数和
a&
参数之间存在任何实际的语义差异,我会感到惊讶。因此,我想这是问我问题的另一种方式:为什么编译器认为对临时值的
常量
引用是安全的,而非
常量
引用则不是安全的?

当您为常量引用指定一个r值时,可以保证在该引用被销毁之前不会销毁临时值。当您分配给非常量引用时,不会做出此类保证

int main()
{
   const A& a2= A(); // this is fine, and the temporary will last until the end of the current scope.
   A& a1 = A(); // You can't do this.
}

你不可能安全地任性地抛弃const-ness,期望事情会成功。常量引用和非常量引用有不同的语义

并不是不能获取地址(编译器总是可以命令将地址推到堆栈上,这与ref to const有关),而是程序员的意图问题。对于一个带a&的接口,它表示“我将修改此参数中的内容,以便您可以在函数调用后读取”。如果你给它一个临时的,那么它“修改”的东西在函数之后就不存在了。这(可能)是一个编程错误,因此是不允许的。例如,考虑:

void plus_one(int & x) { ++x; }

int main() {
   int x = 2;
   float f = 10.0;

   plus_one(x); plus_one(f);

   cout << x << endl << f << endl;
}
void+one(int&x){++x;}
int main(){
int x=2;
浮动f=10.0;
加一(x);加一(f);

一些人可能会遇到这样一个问题:MSVC编译器(Visual Studio编译器,通过Visual Studio 2008验证)将毫无问题地编译此代码。我们在一个项目中使用此范例处理通常只需要一个参数的函数(要摘要的数据块),但有时希望搜索区块并将结果返回给调用者。另一种模式是通过使用三个参数启用的——第二个参数是要搜索的信息(默认引用为空字符串),第三个参数是返回数据(默认引用为所需类型的空列表)

这个范例在VisualStudio2005和2008中都有效,我们必须对其进行重构,以便构建并返回列表,而不是由调用者拥有,并进行变异,以使用g++进行编译


如果有一种方法可以将编译器开关设置为在MSVC中不允许这种行为,或者在g++中允许这种行为,我会很高兴知道;MSVC编译器的允许性/g++编译器的限制性增加了代码移植的复杂性。

我同意这类事情通常是程序员的错误。如果你好奇的话s、 我试图作为引用传递的类是一种智能指针,它有一个底层堆分配的指针成员。我确实希望接收函数处理底层指针。我只想确保临时智能指针没有被破坏(减少引用计数)直到接收函数返回。如果这是您的意图,可以显式声明堆栈上的智能指针并传入,也可以按值传入。如果按值传入,则可以保证在函数退出之前它不会被销毁。@Ben-在我的帖子中添加了一些关于它的内容。如果没有它,您不能说这是否是一个好主意查看您的代码,但有一些用例(在它返回之前不会被销毁)一般来说,临时文件在计算创建它的表达式时会被销毁。当临时文件的生存期延长时,有两个例外,其中一个由@Eclipse指出。请参阅:
ofstream("bar.t") << "flah";
ofstream("bar.t").flush() << "flah";