使用引用初始化class个成员
Use reference to initialize class members
我一直觉得我不应该使用引用来初始化 class 成员,因为
- 我不知道引用的生命周期和
- 如果参考值在 class 之外发生变化,相应的 class 成员也会更改为新值。
但是测试了下面的代码后,我很困惑...
class Test
{
public:
Test(int& i) :m_i(i) {}
int m_i;
};
class Test3
{
public:
Test3(int& i) :m_i(i) {}
const int& m_i;
};
int main()
{
{
std::cout << "\n// Test 1" << std::endl;
int i = 10;
Test oTest(i);
printf("oTest.i = %d\n", oTest.m_i);
i = 20;
printf("oTest.i = %d\n", oTest.m_i);
}
{
std::cout << "\n// Test 1.1" << std::endl;
int* i = new int;
*i = 10;
Test oTest(*i);
printf("oTest.i = %d\n", oTest.m_i);
*i = 20;
printf("oTest.i = %d\n", oTest.m_i);
delete i;
printf("oTest.i = %d\n", oTest.m_i);
}
{
std::cout << "\n// Test 3" << std::endl;
int i = 10;
Test3 oTest(i);
printf("oTest.i = %d\n", oTest.m_i);
i = 20;
printf("oTest.i = %d\n", oTest.m_i);
}
{
std::cout << "\n// Test 3.1" << std::endl;
int* i = new int;
*i = 10;
Test3 oTest(*i);
printf("oTest.i = %d\n", oTest.m_i);
*i = 20;
printf("oTest.i = %d\n", oTest.m_i);
delete i;
printf("oTest.i = %d\n", oTest.m_i);
}
return 0;
}
输出如下:
// Test 1
oTest.i = 10
oTest.i = 10 <---- Why not 20?
// Test 1.1
oTest.i = 10
oTest.i = 10 <---- Why not 20?
oTest.i = 10 <---- Why not some garbage number?
// Test 3
oTest.i = 10
oTest.i = 20
// Test 3.1
oTest.i = 10
oTest.i = 20
oTest.i = 20 <---- Why not some garbage number?
非常感谢您的评论。
你的 Test(int& i) :m_i(i)
调用了一个 copy 构造函数,并且由于你的字段是一个 int,而不是一个 int&,测试 1 和 1.1 总是打印原始的 10。
在测试 3.1 中,没有要求 访问已经freed/deleted 的内存会产生垃圾。 (有些调试编译器故意 在释放的内存中放置 一个不同的模式,但这是它们调试性质的一部分。)你的玩具程序中没有任何东西改变 [=指向的值=11=],所以你“侥幸逃脱”。在企业程序中,你会得到一个hard-to-find "Heisenbug".
我一直觉得我不应该使用引用来初始化 class 成员,因为
- 我不知道引用的生命周期和
- 如果参考值在 class 之外发生变化,相应的 class 成员也会更改为新值。
但是测试了下面的代码后,我很困惑...
class Test
{
public:
Test(int& i) :m_i(i) {}
int m_i;
};
class Test3
{
public:
Test3(int& i) :m_i(i) {}
const int& m_i;
};
int main()
{
{
std::cout << "\n// Test 1" << std::endl;
int i = 10;
Test oTest(i);
printf("oTest.i = %d\n", oTest.m_i);
i = 20;
printf("oTest.i = %d\n", oTest.m_i);
}
{
std::cout << "\n// Test 1.1" << std::endl;
int* i = new int;
*i = 10;
Test oTest(*i);
printf("oTest.i = %d\n", oTest.m_i);
*i = 20;
printf("oTest.i = %d\n", oTest.m_i);
delete i;
printf("oTest.i = %d\n", oTest.m_i);
}
{
std::cout << "\n// Test 3" << std::endl;
int i = 10;
Test3 oTest(i);
printf("oTest.i = %d\n", oTest.m_i);
i = 20;
printf("oTest.i = %d\n", oTest.m_i);
}
{
std::cout << "\n// Test 3.1" << std::endl;
int* i = new int;
*i = 10;
Test3 oTest(*i);
printf("oTest.i = %d\n", oTest.m_i);
*i = 20;
printf("oTest.i = %d\n", oTest.m_i);
delete i;
printf("oTest.i = %d\n", oTest.m_i);
}
return 0;
}
输出如下:
// Test 1
oTest.i = 10
oTest.i = 10 <---- Why not 20?
// Test 1.1
oTest.i = 10
oTest.i = 10 <---- Why not 20?
oTest.i = 10 <---- Why not some garbage number?
// Test 3
oTest.i = 10
oTest.i = 20
// Test 3.1
oTest.i = 10
oTest.i = 20
oTest.i = 20 <---- Why not some garbage number?
非常感谢您的评论。
你的 Test(int& i) :m_i(i)
调用了一个 copy 构造函数,并且由于你的字段是一个 int,而不是一个 int&,测试 1 和 1.1 总是打印原始的 10。
在测试 3.1 中,没有要求 访问已经freed/deleted 的内存会产生垃圾。 (有些调试编译器故意 在释放的内存中放置 一个不同的模式,但这是它们调试性质的一部分。)你的玩具程序中没有任何东西改变 [=指向的值=11=],所以你“侥幸逃脱”。在企业程序中,你会得到一个hard-to-find "Heisenbug".