有人可以解释一下这段代码吗?我不明白怎么
c2的值只有1。
我更喜欢 gdb,但我拒绝将匿名实例与(编译器提供的)默认 ctor、dtor 等结合使用。似乎没有地方可以设置断点或 cout 或介入...在总成层面上的工作太多。
您可能考虑的另一种选择是添加一些诊断 cout 的 ... 以及复制和移动 ctors 以及带有诊断 cout 的 dtor。
也许:
#include <iostream>
class Test
{
private:
int m_seq;
int c2;
static int c1;
public:
Test() // default ctor
: m_seq(++M_seq)
, c2 (0)
{
std::cout << "\n ctor " << show() << std::flush;
}
Test(const Test& rhs) // copy ctor
: m_seq(++M_seq) // unique seq id
, c2 (rhs.c2)
{
std::cout << "\n cctor " << show() << std::flush;
}
Test(const Test&& rhs) // move ctor (4)
: m_seq(++M_seq) // unique seq id
, c2 (rhs.c2)
{
std::cout << "\n mctor " << show() << std::flush;
} // tbd - new to me, should this be something with std::move() ?
~Test() // default dtor
{
std::cout << "\n dtor " << show() << std::flush;
}
Test fun();
int getC1() { return c1; }
int getC2() { return c2; }
std::string show()
{
std::string s;
s = " show() seq: " + std::to_string(m_seq)
+ " c1: " + std::to_string(c1)
+ " c2: " + std::to_string(c2);
return (s);
}
public:
static int M_seq; // diagnostic only
private:
// coding standard - disallow when not used
Test& operator= (const Test&) = delete; // copy assignment (5)
Test& operator= (const Test&&) = delete; // move assignment (6)
};
int Test::c1 = 0;
int Test::M_seq = 0;
Test Test::fun()
{
c2 += ++Test::c1;
// diagnostic only
std::cout << "\n fun() " << show() << std::flush;
return *this;
}
int main(int, char**)
{
// confirm initial seq state
std::cout << "\n -- init M_seq " << Test::M_seq << std::endl;
Test t;
Test t2 = t.fun().fun().fun().fun();
std::cout << "\n\n t final " << t.show() << std::endl;
std::cout << "\n t2 final " << t2.show() << std::endl;
// note how easy to ignore getters -
// see http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html
// final seq state
std::cout << "\n\n - final M_seq " << Test::M_seq << std::endl;
}
有输出:
-- init M_seq 0
ctor show() seq: 1 c1: 0 c2: 0
fun() show() seq: 1 c1: 1 c2: 1
cctor show() seq: 2 c1: 1 c2: 1
fun() show() seq: 2 c1: 2 c2: 3
cctor show() seq: 3 c1: 2 c2: 3
fun() show() seq: 3 c1: 3 c2: 6
cctor show() seq: 4 c1: 3 c2: 6
fun() show() seq: 4 c1: 4 c2: 10
cctor show() seq: 5 c1: 4 c2: 10
dtor show() seq: 4 c1: 4 c2: 10
dtor show() seq: 3 c1: 4 c2: 6
dtor show() seq: 2 c1: 4 c2: 3
t final show() seq: 1 c1: 4 c2: 1
t2 final show() seq: 5 c1: 4 c2: 10
- final M_seq 5
dtor show() seq: 5 c1: 4 c2: 10
dtor show() seq: 1 c1: 4 c2: 1
c2的值只有1
此输出列出了 ctor、fun() 和 cctor 调用。
现在每个匿名对象都会打印其唯一的 m_seq,因此 seq id 应该有助于查看“操作”发生的位置。
第一个 ctor 得到 seq 的 1 ...第一个 fun() 也是 seq 1 - 有意义。
fun() 的后续调用在不同的实例中,最后 3 个是匿名的,这使得调试变得混乱。
你是对的 - 第一个实例(带有 seq 1)以 c2 值 1 结束。以后 fun() 不会更改它。
你也是正确的,最后一个实例(seq 5)以 c2 值 10 结束。
在 4 个 fun() 链接在一起的序列中,最后 3 个创建 Test 的“临时”匿名实例,以及 2、3 和 4 个 dtor 与它们 ctor 在同一行。
这种技术(使用诊断 couts 检测代码)很常见。在任何诊断 cout 前面加上一个 bool 以启用/禁用以进行更正式的测试……如果您不希望附带噪音,则在前面加上一个 bool 标识符以便于查找/删除。 (在生产代码中,我使用了基于 ram-based-round-robin 的日志。为了发布,此日志在系统启动时被抑制,并且没有日志会取消额外的 cout 活动。)
您可以通过让 Test::fun() 返回指向实例的指针来真正改变这段代码的行为:Test*。该函数当前返回一个 Test 实例(即 *this),因此编译器生成一个 cctor 来构造该新的匿名实例。返回 this 指针会将 fun() 链更改为 fun()->fun()->fun()->fun()。
希望这会有所帮助。