这与a question posted yesterday有关。
class A
{
public:
mutable int x;
A()
{
static int i = 0;
x = i;
i++;
std::cout << " A()" << std::endl;
}
~A()
{
std::cout << "~A()" << std::endl;
}
void foo() const
{
x = 1;
};
};
class B
{
public:
const A & a;
B(const A & a) : a(a)
{
std::cout << " B()" << std::endl;
}
~B()
{
std::cout << "~B()" << std::endl;
}
void doSomething()
{
a.foo();
};
};
int main()
{
B b((A()));
b.doSomething();
}
现在,在调用doSomething之前调用了析构函数。但是,虽然该函数基本上更改了A的成员,但调用仍然有效。它是不是同一个实例。没有其他A创建。我使用A的构造函数中的静态来跟踪它。谁能解释一下?
答案 0 :(得分:6)
这是未定义的行为,因此没有语言标准解释。
然而,A
的析构函数对存储x
的内存区域没有任何作用,所以如果你稍后看一下该值可能仍然存在。或者,如果您尝试写入地址,地址仍然存在。你不能这样做。
答案 1 :(得分:0)
以此为例
class B
{
public:
const std::string & a;
B(const std::string & a) : a(a)
{
std::cout << " B()" << std::endl;
}
~B()
{
std::cout << "~B()" << std::endl;
}
void doSomething()
{
std::cout << "a = " << a << std::endl;
};
};
int main()
{
B b(std::string("I love C++ so much!"));
b.doSomething();
}
答案 2 :(得分:0)
博是正确的。
此外,您可以检查存储“A”的地址,并确认该地址尚未被重用(请记住析构函数释放(“释放”)内存,但不会t遍历数据结构,将所有位设置回0;这将是低效的。)
例如,如果您发现A存储在堆栈顶部,那么您很幸运,您的后续函数调用未传入参数,因为这会覆盖A的内存区域。
答案 3 :(得分:0)
扩大Bo的答案。
对于临时存在,将在堆栈上保留空间。只要语义要求临时存在,这个空间实际上是保留的,然后可以重用其他东西。
如果你在重用后尝试使用内存,你会发现一种奇怪的行为(未定义行为的定义是任何事情都可能发生)。实际上,你运气并且内存仍然存在,处于您期望的状态。
示例:
#include <iostream>
struct A {
A(): p(0) {}
~A() { if (p) { std::cout << *p << "\n"; } }
int* p;
};
int bar0();
void bar1(int i);
int main() {
A a;
{
int x = 4; a.p = &x;
}
{
int y = bar0(); bar1(y);
}
}
int bar0() { return 7; }
void bar1(int i) { std::cout << i << "\n"; }
在这里,编译器可以选择为x
重用y
的空间,或者只是做任何想做的事情,因此你实际上是在打印垃圾。
这是gcc 4.3.4(和4.5.1)输出(由ideone提供):
7
4
意味着空间不会与那些空间重复使用......