[英]c++, object life-time of anonymous (unnamed) variables
在下面的代码中,'main()'最后一行构造的对象似乎在表达式结束之前被销毁了。 析构函数在执行 '<<' 之前被调用。 这是应该的吗?
#include <string>
#include <sstream>
#include <iostream>
using std::string;
using std::ostringstream;
using std::cout;
class A : public ostringstream
{
public:
A () {}
virtual ~A ()
{
string s;
s = str();
cout << "from A: " << s << std::endl;
}
};
int
main ()
{
string s = "Hello";
A os;
os << s;
cout << os.str() << std::endl;
A() << "checking this";
}
这是输出:
Hello
from A: 0x80495f7
from A: Hello
这是 gdb 日志:
(gdb) b os.cxx : 18
Breakpoint 1 at 0x80492b1: file os.cxx, line 18. (2 locations)
(gdb) r
Starting program: /home/joe/sandbox/test/os
Hello
Breakpoint 1, ~A (this=0xbffff37c, __in_chrg=<value optimized out>, __vtt_parm=<value optimized out>) at os.cxx:18
18 cout << "from A: " << s << std::endl;
(gdb) p s.c_str ()
$1 = 0x804b45c "0x80495f7"
(gdb) p *s.c_str ()
$2 = 48 '0'
(gdb) c
Continuing.
from A: 0x80495f7
Breakpoint 1, ~A (this=0xbffff2bc, __in_chrg=<value optimized out>, __vtt_parm=<value optimized out>) at os.cxx:18
18 cout << "from A: " << s << std::endl;
(gdb) p s.c_str ()
$3 = 0x804b244 "Hello"
(gdb) p *s.c_str ()
$4 = 72 'H'
(gdb) c
Continuing.
from A: Hello
Program exited normally.
(gdb)
直到执行完整语句后,才会删除 A。
您遇到的问题不是由 A 被删除和打印未初始化的数据引起的,而是由 r 值引用引起的。 匿名实例只能通过值或常量引用传递。
这意味着您的类将支持operator <<
定义为成员函数而不是全局函数。
为了展示这个尝试
struct A {
f()
};
void g(A & a) {
}
void foo() {
A a;
a.f();
g(a);
A().f();
g(A()); // This does not compile
}
我实现了类似于您的 A 类的日志记录机制。它在 Visual Studio 6 中运行良好,但在 Visual Studio 2005 中运行良好。我通过使用委托而不是继承来修复它。
class A
{
ostringstream mystream;
public:
A () {}
virtual ~A ()
{
cout << "from A: " << mystream.str(); << std::endl;
}
ostream & stream()
{
return mystream;
}
};
int
main ()
{
string s = "Hello";
A os;
os.stream() << s;
A().stream() << "checking this";
}
我假设您计划将它与日志记录和可能的宏一起使用。 这就是我根据上面的 A 使用我的类的方式。
#define TRACE_ERROR if (A::testLevel(A::Error) A(A::Error).stream()
#define TRACE_INFO if (A::testLevel(A::Info) A(A::Info).stream()
然后在代码中
void foo()
{
int a = ..
std::string s = ..
TRACE_INFO << "Some information " << a << " message: " s;
}
我相信您所看到的行为是因为“匿名临时对象不能作为非常量引用传递给函数”的规则(实际上并非如此,但在不同的编译器上具有未定义的行为或不同的行为)。 因此,它确实转到最后一行的 << 运算符,但它找到了 << 运算符的 member(const void*) 重载而不是自由函数 (const char*) 重载,主要是因为上述规则. 因此,临时 A 被构造,并传递给 << 运算符,该运算符返回非常量引用。
因此,现在 operator<<(const void*) 被定义为类的成员,而 operator<<(const char*) 是一个自由函数。 当在非常量临时函数上调用函数时,在成员函数中查找唯一与参数匹配的函数,并且没有与之匹配的自由函数。 我知道 MSVC 与 GCC 有不同的行为。
事实上,如果您尝试将字符串“checking this”更改为较小的字符串,以便您可以看到它的值(将其从 char* 转换为 void* 并查看您得到的值),您将看到它打印的内容实际上是 void* cast的“检查这个”。 所以析构函数在最后被调用,但 << 已将 char* 转换为 void* ,这就是打印的内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.