共享取消引用的指针值显示不同的结果(应用隐式复制构造函数时)。为什么?
Shared dereferenced pointer value displays different results (when applying implicit copy constructor). Why?
这段代码的输出是
21
我无法向自己解释。我的想法(我学到的)是调用 隐式复制构造函数 (由 赋值 触发)并且所有元素都被一点一点地复制。但是,这不适用于外部元素,例如私有变量 val
,它是一个指针。所以b
有一个不同的指针,但是它指向同一个元素。
所以我预计结果是
22
即 .get()
被 a
和 b
调用两次,因此取消引用的指针值应该是 1
(在第一个 get()
之后)然后是 2
(在第二个 get()
之后)。最后,这些值被写入控制台输出。
C++代码:
#include <iostream>
using namespace std;
class A {
int *val;
public:
A() {
val = new int;
*val = 0;
}
int get() {
return ++(*val);
}
};
int main() {
A a, b = a;
cout << a.get() << b.get();
return 0;
}
使用 cout 时,a.get()
和 b.get()
的计算没有特定的顺序。因此,在您的示例中,首先评估 b.get()
(到 1),然后评估 a.get()
(到 2),然后在屏幕上打印“21”。
您的问题是序列点之一:std::cout << a.get() << b.get();
没有严格定义 a.get()
和 b.get()
的求值顺序。
有关所有解释,请参阅 this answer here。
首先为对象 b 调用 get 函数,然后为对象 a 调用,因此 o/p 为 2 1
(gdb) s
main () at so2.c++:20
20 cout << a.get() << b.get();
(gdb) p &a
= (A *) **0x7fffffffd0f0**
(gdb) p &b
= (A *) *0x7fffffffd0e0*
(gdb) s
A::get (this=*0x7fffffffd0e0*) at so2.c++:14
14 return ++(*val);
(gdb) p *val
= 0
(gdb) n
15 }
(gdb) p *val
= 1
(gdb) s
A::get (**this=0x7fffffffd0f0**) at so2.c++:14
14 return ++(*val);
(gdb) s
15 }
(gdb) p *val
= 2
从上面的调试会话中我们可以看到流程和行为。
这就是代码的实际作用:
cout.operator<<( a.get() ).operator<<( b.get() );
或
operator<<( operator<<( cout, a.get() ), b.get() );
(由于重载问题,我无法让后者编译,但它确实发生在幕后)
这意味着代码在 b.get() 之前计算 std::endl,在 a.get() 之前计算 b.get()。所以 b.get() 将 val 的指向值增加 1,然后 returns 1,并且 a.get() 将 val 的指向值增加 1 和 returns 2。运算符被调用评估参数后的预期顺序。我猜这取决于编译器,但我 运行 你的代码也得到了 21。
在这种情况下,您使用的是隐式复制构造函数。它所做的是将你的实例a的内存复制到实例b。 (如你所说,逐字节)
所以 b 现在拥有自己的指针,该指针与 a 的指针具有相同的值,即指向相同的地址。由于您增加了 get() 的值,返回的值永远不会相同,因此您永远不会得到 22。
编辑:你实际上没有使用std::endl,这是我的习惯。
这段代码的输出是
21
我无法向自己解释。我的想法(我学到的)是调用 隐式复制构造函数 (由 赋值 触发)并且所有元素都被一点一点地复制。但是,这不适用于外部元素,例如私有变量 val
,它是一个指针。所以b
有一个不同的指针,但是它指向同一个元素。
所以我预计结果是
22
即 .get()
被 a
和 b
调用两次,因此取消引用的指针值应该是 1
(在第一个 get()
之后)然后是 2
(在第二个 get()
之后)。最后,这些值被写入控制台输出。
C++代码:
#include <iostream>
using namespace std;
class A {
int *val;
public:
A() {
val = new int;
*val = 0;
}
int get() {
return ++(*val);
}
};
int main() {
A a, b = a;
cout << a.get() << b.get();
return 0;
}
使用 cout 时,a.get()
和 b.get()
的计算没有特定的顺序。因此,在您的示例中,首先评估 b.get()
(到 1),然后评估 a.get()
(到 2),然后在屏幕上打印“21”。
您的问题是序列点之一:std::cout << a.get() << b.get();
没有严格定义 a.get()
和 b.get()
的求值顺序。
有关所有解释,请参阅 this answer here。
首先为对象 b 调用 get 函数,然后为对象 a 调用,因此 o/p 为 2 1
(gdb) s
main () at so2.c++:20
20 cout << a.get() << b.get();
(gdb) p &a
= (A *) **0x7fffffffd0f0**
(gdb) p &b
= (A *) *0x7fffffffd0e0*
(gdb) s
A::get (this=*0x7fffffffd0e0*) at so2.c++:14
14 return ++(*val);
(gdb) p *val
= 0
(gdb) n
15 }
(gdb) p *val
= 1
(gdb) s
A::get (**this=0x7fffffffd0f0**) at so2.c++:14
14 return ++(*val);
(gdb) s
15 }
(gdb) p *val
= 2
从上面的调试会话中我们可以看到流程和行为。
这就是代码的实际作用:
cout.operator<<( a.get() ).operator<<( b.get() );
或
operator<<( operator<<( cout, a.get() ), b.get() );
(由于重载问题,我无法让后者编译,但它确实发生在幕后)
这意味着代码在 b.get() 之前计算 std::endl,在 a.get() 之前计算 b.get()。所以 b.get() 将 val 的指向值增加 1,然后 returns 1,并且 a.get() 将 val 的指向值增加 1 和 returns 2。运算符被调用评估参数后的预期顺序。我猜这取决于编译器,但我 运行 你的代码也得到了 21。
在这种情况下,您使用的是隐式复制构造函数。它所做的是将你的实例a的内存复制到实例b。 (如你所说,逐字节)
所以 b 现在拥有自己的指针,该指针与 a 的指针具有相同的值,即指向相同的地址。由于您增加了 get() 的值,返回的值永远不会相同,因此您永远不会得到 22。
编辑:你实际上没有使用std::endl,这是我的习惯。