C ++, object lifetime of anonymous (unnamed) variables

In the following code, the object built in the last line of 'main ()' seems to be destroyed to the end of the expression. The destructor is called before '<is executed. Is that how it should be?

#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"; } 

This is the conclusion:

 Hello from A: 0x80495f7 from A: Hello 

This is gdb log:

 (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) 
+3
source share
2 answers

I believe that the behavior you see is due to the fact that "anonymous temporary data cannot be passed to functions as non-constant links" (well, not really NOT, but they have undefined behavior or different behaviors on different compilers), Thus , it goes to the <operator in the last line, but it detects an element overload (const void *) for the <operator, not an overload (const char *) overload, mainly due to the rule above. Thus, temporary A is built and passed to the <operator, which returns a non-constant reference.

Thus, now the operator <(const void *) is defined as a member of the class, while the operator <(const char *) is a free function. When a function is called in non-constant time mode, the only function corresponding to the argument is looked up in member functions and no free functions are mapped to it. I know that MSVC treats GCC differently.

Infact, if you try to change the string "checking this" to something less so that you can see its value (convert it from char * to void * and see what value you get), you will see that it actually prints void * cast of "check this out." Thus, the destructor is called at the very end, but <made a char * for void *, and that is what is printed.

+2
source

A is not deleted until a complete statement is executed.

The problem you are experiencing is not caused by the fact that A is deleted and prints uninitialized data, but refers to r-value references. Anonymous instances can only be passed by value or constant reference.

This means that your class will support operator << , defined as member functions, but not as global functions.

To show this attempt

 struct A { f() }; void g(A & a) { } void foo() { A a; af(); g(a); A().f(); g(A()); // This does not compile } 

I implemented a registration mechanism similar to your class A. It worked fine with Visual Studio 6, but not with Visual Studio 2005. I fixed it using delegation instead of inheritance.

 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"; } 

I assume that you plan to use this with logging and probably with a macro. This is how I use my class based on the above.

 #define TRACE_ERROR if (A::testLevel(A::Error) A(A::Error).stream() #define TRACE_INFO if (A::testLevel(A::Info) A(A::Info).stream() 

then in code

 void foo() { int a = .. std::string s = .. TRACE_INFO << "Some information " << a << " message: " s; } 
+4
source

Source: https://habr.com/ru/post/1307923/


All Articles