I'd like to understand where a class' ostream operator "lives" in an object file. In the code sample below, I have contrived C++ class DeltaTimer that friends an ostream operator. Further below is the output of "nm DeltaTimer.o". Grepping for "ostream" in this output shows them against symbol type "U", i.e. undefined. But the code compiles (main.cpp included for completeness) and links successfully, and executes as expected, meaning nothing is undefined. But I don't understand what the ostream operator resolves to in the output of "nm" and would appreciate if anyone can advise. Thank you.
DeltaTimer.h:
#ifndef DeltaTimer_h
#define DeltaTimer_h
#include <iostream>
class DeltaTimer
{
public:
DeltaTimer();
virtual ~DeltaTimer();
void Foo();
private:
int m_foo;
friend std::ostream& operator<<(std::ostream& os, const DeltaTimer& rDeltaTimer);
};
#endif // DeltaTimer_h
DeltaTimer.cpp:
#include "DeltaTimer.h"
#include <iostream>
DeltaTimer::DeltaTimer() : m_foo(5)
{
std::cout << "DeltaTimer ctor" << std::endl;
}
DeltaTimer::~DeltaTimer()
{
std::cout << "DeltaTimer dtor" << std::endl;
}
void DeltaTimer::Foo()
{
std::cout << "DeltaTimer.m_foo == " << m_foo << std::endl;
}
std::ostream& operator<<(std::ostream& os, const DeltaTimer& rDeltaTimer)
{
os << "DeltaTimer[m_foo(" << rDeltaTimer.m_foo << ")]" << std::endl;
}
// This function is just a sanity-check for the output of "nm"
void Bar()
{
std::cout << "void Bar()" << std::endl;
}
main.cpp:
#include "DeltaTimer.h"
#include <iostream>
int main()
{
DeltaTimer deltaTimer;
std::cout << deltaTimer << std::endl;
}
Output of "nm":
>nm DeltaTimer.o
00000000000001a7 t _GLOBAL__I__ZN10DeltaTimerC2Ev
0000000000000145 T _Z3Barv
0000000000000167 t _Z41__static_initialization_and_destruction_0ii
00000000000000b0 T _ZN10DeltaTimer3FooEv
0000000000000000 T _ZN10DeltaTimerC1Ev
0000000000000000 T _ZN10DeltaTimerC2Ev
000000000000008a T _ZN10DeltaTimerD0Ev
0000000000000040 T _ZN10DeltaTimerD1Ev
0000000000000040 T _ZN10DeltaTimerD2Ev
U _ZNSolsEPFRSoS_E
U _ZNSolsEi
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
U _ZSt4cout
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
0000000000000000 b _ZStL8__ioinit
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
0000000000000000 V _ZTI10DeltaTimer
0000000000000000 V _ZTS10DeltaTimer
0000000000000000 V _ZTV10DeltaTimer
U _ZTVN10__cxxabiv117__class_type_infoE
U _ZdlPv
00000000000000f1 T _ZlsRSoRK10DeltaTimer
U __cxa_atexit
U __dso_handle
U __gxx_personality_v0
>nm DeltaTimer.o | grep -i ostream
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
Thta's because nm
is showing mangled names. To print human readable ones, you'll want to use the --demangle
argument:
$ nm --demangle DeltaTimer.o
U __cxa_atexit
U __dso_handle
00000000000001a4 t _GLOBAL__sub_I__ZN10DeltaTimerC2Ev
U __gxx_personality_v0
0000000000000145 T Bar()
0000000000000167 t __static_initialization_and_destruction_0(int, int)
U operator delete(void*)
00000000000000f1 T operator<<(std::ostream&, DeltaTimer const&) // <== here's your guy!
00000000000000b0 T DeltaTimer::Foo()
0000000000000000 T DeltaTimer::DeltaTimer()
0000000000000000 T DeltaTimer::DeltaTimer()
000000000000008a T DeltaTimer::~DeltaTimer()
0000000000000040 T DeltaTimer::~DeltaTimer()
0000000000000040 T DeltaTimer::~DeltaTimer()
U std::ostream::operator<<(int)
U std::ostream::operator<<(std::ostream& (*)(std::ostream&))
U std::ios_base::Init::Init()
U std::ios_base::Init::~Init()
U std::cout
U std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
0000000000000000 r std::piecewise_construct
0000000000000000 b std::__ioinit
U std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
0000000000000000 V typeinfo for DeltaTimer
0000000000000000 V typeinfo name for DeltaTimer
0000000000000000 V vtable for DeltaTimer
U vtable for __cxxabiv1::__class_type_info
Or just use c++filt
is for. Specifically:
$ echo _ZlsRSoRK10DeltaTimer | c++filt
operator<<(std::basic_ostream<char, std::char_traits<char> >&, DeltaTimer const&)