我刚刚意识到这个程序可以编译和运行(gcc 版本 4.4.5/Ubuntu):
#include <iostream>
using namespace std;
class Test
{
public:
// copyconstructor
Test(const Test& other);
};
Test::Test(const Test& other)
{
if (this == &other)
cout << "copying myself" << endl;
else
cout << "copying something else" << endl;
}
int main(int argv, char** argc)
{
Test a(a); // compiles, runs and prints "copying myself"
Test *b = new Test(*b); // compiles, runs and prints "copying something else"
}
我不知道为什么这甚至可以编译。我假设(就像在 Java 中一样)在调用方法/构造函数之前评估参数,所以我怀疑这种情况必须由语言规范中的某些“特殊情况”涵盖?
问题:
- 有人可以解释一下吗(最好是引用规范)?
- 允许这样做的理由是什么?
- 它是标准 C++ 还是特定于 gcc 的?
编辑 1:我刚刚意识到我什至可以写 int i = i;
编辑 2:即使使用 -Wall
和 -pedantic
,编译器也不会提示 Test a(a);
。
编辑 3:如果我添加一个方法
Test method(Test& t)
{
cout << "in some" << endl;
return t;
}
我什至可以在没有任何警告的情况下执行 Test a(method(a));
。
最佳答案
这个“被允许”的原因是因为规则说标识符范围在标识符之后立即开始。在这种情况下
int i = i;
RHS i 在 LHS i“之后”,所以 i 在范围内。这并不总是坏事:
void *p = (void*)&p; // p contains its own address
因为可以在不使用变量值的情况下对变量进行寻址。在 OP 的复制构造函数的情况下,不会轻易给出错误,因为绑定(bind)对变量的引用不需要初始化变量:它等同于获取变量的地址。合法的构造函数可以是:
struct List { List *next; List(List &n) { next = &n; } };
你看到的参数只是被处理,它的值没有被使用。在这种情况下,自引用实际上是有意义的:列表的尾部由自引用给出。实际上,如果您将“next”的类型更改为引用,则别无选择,因为您不能像对指针那样轻松地使用 NULL。
像往常一样,问题是倒退的。问题不是为什么变量的初始化可以引用自身,问题是为什么它不能向前引用。 [在 Felix 中,这是可能的]。特别是,对于与变量相反的类型,缺乏转发引用的能力是非常糟糕的,因为它阻止了递归类型的定义,而不是通过使用不完整的类型,这在 C 中就足够了,但在 C++ 中就不够了,因为存在模板。
关于c++ - 以自身为引用构造对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4368361/