Is it possible to take the address of an ADL function? - c++

Is it possible to take the address of a function that would be found through ADL?
For example:
template<class T>
void (*get_swap())(T &, T &)
{
return & _________; // how do I take the address of T's swap() function?
}
int main()
{
typedef some_type T;
get_swap<T>();
}

Honestly, I don't know but I tend towards saying that this is not possible.
Depending on what you want to achieve I can suggest a workaround. More precisely, if you just need the address of a function that has the same semantics as swap called through ADL then you can use this:
template <typename T>
void (*get_swap())(T&, T&) {
return [](T& x, T& y) { return swap(x, y); };
}
For instance, the following code:
namespace a {
struct b {
int i;
};
void swap(b& x, b& y) {
std::swap(x.i, y.i);
}
}
int main() {
auto f0 = (void (*)(a::b&, a::b&)) a::swap;
auto f1 = get_swap<a::b>();
std::cout << std::hex;
std::cout << (unsigned long long) f0 << '\n';
std::cout << (unsigned long long) f1 << '\n';
}
compiled with gcc 4.8.1 (-std=c++11 -O3) on my machine gave:
4008a0
4008b0
The relevant assembly code (objdump -dSC a.out) is
00000000004008a0 <a::swap(a::b&, a::b&)>:
4008a0: 8b 07 mov (%rdi),%eax
4008a2: 8b 16 mov (%rsi),%edx
4008a4: 89 17 mov %edx,(%rdi)
4008a6: 89 06 mov %eax,(%rsi)
4008a8: c3 retq
4008a9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
00000000004008b0 <void (*get_swap<a::b>())(a::b&, a::b&)::{lambda(a::b&, a::b&)#1}::_FUN(a::b&, a::b&)>:
4008b0: 8b 07 mov (%rdi),%eax
4008b2: 8b 16 mov (%rsi),%edx
4008b4: 89 17 mov %edx,(%rdi)
4008b6: 89 06 mov %eax,(%rsi)
4008b8: c3 retq
4008b9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
As one can see the functions pointed by f0 and f1 (located at 0x4008a0 and 0x4008b0, respectively) are binary identical. The same holds when compiled with clang 3.3.
If the linker can do identical COMDAT folding (ICF), I guess, we can even get f0 == f1. (For more on ICF see this post.)

Related

Weird behavior in GDB when defaulting copy/move constructors

I have the following code which seems to behave weirdly in GDB depending if the copy/move constructors are defaulted or not.
#include <iostream>
#define CUSTOM 0
class Percentage
{
public:
using value_t = double;
Percentage() = default;
~Percentage() = default;
template <typename T>
Percentage(T) = delete;
Percentage(value_t value):
m_value(value)
{}
#if CUSTOM == 1
Percentage(const Percentage& p):
m_value(p.m_value)
{}
Percentage& operator=(const Percentage& p)
{
m_value = p.m_value;
return *this;
}
Percentage(Percentage&& p):
m_value(std::move(p.m_value))
{}
Percentage& operator=(Percentage&& p)
{
m_value = std::move(p.m_value);
return *this;
}
#else
Percentage(const Percentage&) = default;
Percentage& operator=(const Percentage&) = default;
Percentage(Percentage&&) = default;
Percentage& operator=(Percentage&&) = default;
#endif
friend std::ostream& operator<<(std::ostream& os, const Percentage& p)
{
return os << (p.m_value * 100.0) << '%';
}
private:
value_t m_value = 0.0;
};
struct test
{
Percentage m_p;
void set(const Percentage& v) { m_p = v; }
Percentage get() const { return m_p; }
};
int main()
{
test t;
std::cout << "Value 1: " << t.get() << std::endl;
t.set(42.0);
std::cout << "Value 2: " << t.get() << std::endl;
std::cout << "Breakpoint here" << std::endl;
}
I fire up GDB, add a breakpoint on the last cout in main and run "p t.get()" and I expect it to be 42 but depending on the value of the macro CUSTOM I get either 42 (when CUSTOM is 1) or 0 (when CUSTOM is 0).
What is happening ? Is this a bug in gdb, the compiler ?
OS: Fedora 26
Compiler: gcc 7.3.1
Flags: -fsanitize=address,leak -O0 -g3 -std=c++17
GDB 8.0.1-36
In general since the result of test::get is a "pure rvalue", the compiler is allowed to skip its initialization if its not bound to an lvalue (like a Percentage&&). So to see the content of the a pure rvalue you should store it in a Percentage&& variable, which "materializes" the prvalue and extends the lifetime of the temporary returned.
The difference between the 2 cases seems to exist in the executable (nothing related to GDB): one can see from the disassembly of the executable in the two cases that "test::get" differs, while if we compile with optimization on (-O3) the assembly generated is the same.
Case 0:
Percentage get() { return m_p; }
4009f0: 55 push %rbp
4009f1: 48 89 e5 mov %rsp,%rbp
4009f4: 48 89 7d f0 mov %rdi,-0x10(%rbp)
4009f8: 48 8b 7d f0 mov -0x10(%rbp),%rdi
4009fc: 48 8b 3f mov (%rdi),%rdi
4009ff: 48 89 7d f8 mov %rdi,-0x8(%rbp)
400a03: f2 0f 10 45 f8 movsd -0x8(%rbp),%xmm0
400a08: 5d pop %rbp
400a09: c3 retq
400a0a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
Case 1:
Percentage get() { return m_p; }
4009f0: 55 push %rbp
4009f1: 48 89 e5 mov %rsp,%rbp
4009f4: 48 83 ec 10 sub $0x10,%rsp
4009f8: 48 89 f8 mov %rdi,%rax
4009fb: 48 89 75 f8 mov %rsi,-0x8(%rbp)
4009ff: 48 8b 75 f8 mov -0x8(%rbp),%rsi
400a03: 48 89 45 f0 mov %rax,-0x10(%rbp)
400a07: e8 54 00 00 00 callq 400a60 <_ZN10PercentageC2ERKS_>
400a0c: 48 8b 45 f0 mov -0x10(%rbp),%rax
400a10: 48 83 c4 10 add $0x10,%rsp
400a14: 5d pop %rbp
400a15: c3 retq
400a16: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
400a1d: 00 00 00
Since you call test::get from GDB in this case you are not simply printing a value in memory, you are executing the lines above. You see there's a call to the copy constructor of Percentage, and the return of test::get seems to be in the rax register, while it seems that in the first snippet the implicit constructor is inlined, and the return value is stored in the floating point register xmm0.
I don't know why this difference (maybe someone expert in assembly can add some insight), but I suspect that's why GDB gets confused.

Are inline functions passed as argument, really executed inline in C/C++?

I have a very long (in number of iterations) for loop, and I like to make it possible to personalize some of its parts. The code looks as following:
function expensive_loop( void (*do_true)(int), void (*do_false)(int)){
for(i=0; i<VeryLargeN; i++){
element=elements[i]
// long computation that produce a boolean condition
if (condition){
do_true(element);
}else{
do_false(element);
}
}
}
Now, the problem is that every time do_true and do_false are called, there is an overhead due to the push/pop of the stack that ruins the high performance of the code.
To solve this I could simply create several copies of the expensive_loop function, each with its own do_true and do_false implementation. This will make impossible the code to mantain.
So, how does someone make the internal part of an iteration so it can be personalized, and still mantain high performance?
Note that the function accepts pointers to functions, so those get called through a pointer. The optimizer may inline those calls through the function pointers if the definitions of expensive_loop and those functions are available and the compiler inlining limits have not been breached.
Another option is to make this algorithm a function template that accepts callable objects (function pointers, objects with a call operator, lambdas), just like standard algorithms do. This way the compiler may have more optimization opportunities. E.g.:
template<class DoTrue, class DoFalse>
void expensive_loop(DoTrue do_true, DoFalse do_false) {
// Original function body here.
}
There is -Winline compiler switch for g++:
-Winline
Warn if a function can not be inlined and it was declared as inline. Even with this option, the compiler will not warn about failures to inline functions declared in system headers.
The compiler uses a variety of heuristics to determine whether or not to inline a function. For example, the compiler takes into account the size of the function being inlined and the the amount of inlining that has already been done in the current function. Therefore, seemingly insignificant changes in the source program can cause the warnings produced by -Winline to appear or disappear.
It probably does not warn about a function not being inlined when it is called through a pointer.
The problem is that the function address (what actually is set in do_true and do_false is not resolved until link time, where there are not many opportunities for optimization.
If you are explicitly setting both functions in the code (i.e., the functions themselves don't come from an external library, etc.), you can declare your function with C++ templates, so that the compiler knows exactly which functions you want to call at that time.
struct function_one {
void operator()( int element ) {
}
};
extern int elements[];
extern bool condition();
template < typename DoTrue, typename DoFalse >
void expensive_loop(){
DoTrue do_true;
DoFalse do_false;
for(int i=0; i<50; i++){
int element=elements[i];
// long computation that produce a boolean condition
if (condition()){
do_true(element); // call DoTrue's operator()
}else{
do_false(element); // call DoFalse's operator()
}
}
}
int main( int argc, char* argv[] ) {
expensive_loop<function_one,function_one>();
return 0;
}
The compiler will instantiate an expensive_loop function for each combination of DoTrue and DoFalse types you specify. It will increase the size of the executable if you use more than one combination, but each of them should do what you expect.
For the example I shown, note how the function is empty.
The compiler just strips away the function call and leaves the loop:
main:
push rbx
mov ebx, 50
.L2:
call condition()
sub ebx, 1
jne .L2
xor eax, eax
pop rbx
ret
See example in https://godbolt.org/g/hV52Nn
Using function pointers as in your example, may not inline the function calls. This is the produced assembler for main and expensive_loop in a program where expensive_loop
// File A.cpp
void foo( int arg );
void bar( int arg );
extern bool condition();
extern int elements[];
void expensive_loop( void (*do_true)(int), void (*do_false)(int)){
for(int i=0; i<50; i++){
int element=elements[i];
// long computation that produce a boolean condition
if (condition()){
do_true(element);
}else{
do_false(element);
}
}
}
int main( int argc, char* argv[] ) {
expensive_loop( foo, bar );
return 0;
}
and the functions passed by argument
// File B.cpp
#include <math.h>
int elements[50];
bool condition() {
return elements[0] == 1;
}
inline int foo( int arg ) {
return arg%3;
}
inline int bar( int arg ) {
return 1234%arg;
}
are defined in different translation units.
0000000000400620 <expensive_loop(void (*)(int), void (*)(int))>:
400620: 41 55 push %r13
400622: 49 89 fd mov %rdi,%r13
400625: 41 54 push %r12
400627: 49 89 f4 mov %rsi,%r12
40062a: 55 push %rbp
40062b: 53 push %rbx
40062c: bb 60 10 60 00 mov $0x601060,%ebx
400631: 48 83 ec 08 sub $0x8,%rsp
400635: eb 19 jmp 400650 <expensive_loop(void (*)(int), void (*)(int))+0x30>
400637: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
40063e: 00 00
400640: 48 83 c3 04 add $0x4,%rbx
400644: 41 ff d5 callq *%r13
400647: 48 81 fb 28 11 60 00 cmp $0x601128,%rbx
40064e: 74 1d je 40066d <expensive_loop(void (*)(int), void (*)(int))+0x4d>
400650: 8b 2b mov (%rbx),%ebp
400652: e8 79 ff ff ff callq 4005d0 <condition()>
400657: 84 c0 test %al,%al
400659: 89 ef mov %ebp,%edi
40065b: 75 e3 jne 400640 <expensive_loop(void (*)(int), void (*)(int))+0x20>
40065d: 48 83 c3 04 add $0x4,%rbx
400661: 41 ff d4 callq *%r12
400664: 48 81 fb 28 11 60 00 cmp $0x601128,%rbx
40066b: 75 e3 jne 400650 <expensive_loop(void (*)(int), void (*)(int))+0x30>
40066d: 48 83 c4 08 add $0x8,%rsp
400671: 5b pop %rbx
400672: 5d pop %rbp
400673: 41 5c pop %r12
400675: 41 5d pop %r13
400677: c3 retq
400678: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
40067f: 00
You can see how the calls are still performed even when using -O3 optimization level:
400644: 41 ff d5 callq *%r13

Operator [] long and short versions

What is the advantage of using the longer version (something).operator[]() instead of simply (something)[]?
For example :
std::array<int, 10> arr1;
std::array<int, 10> arr2;
for(int i = 0; i < arr1.size(); i++)
std::cout << arr1[i] << ' ';
std::cout << std::endl;
for(int i = 0; i < arr2.size(); i++)
std::cout << arr2.operator[](i) << ' ';
std::cout << std::endl;
There is none. The [] is just syntactic sugar for operator[] on user-defined types. You only need the operator syntax when you define these functions yourself. This goes for all operators like operator(), operator[], operator new, operator=, ...
syntactic sugar
compiled with g++ -g -std=gnu++0x ...
0000000000400554 <main>:
#include <array>
int main() {
400554: 55 push %rbp
400555: 48 89 e5 mov %rsp,%rbp
400558: 48 83 ec 60 sub $0x60,%rsp
std::array<int, 10> arr1;
std::array<int, 10> arr2;
arr1[6];
40055c: 48 8d 45 d0 lea -0x30(%rbp),%rax
400560: be 06 00 00 00 mov $0x6,%esi
400565: 48 89 c7 mov %rax,%rdi
400568: e8 19 00 00 00 callq 400586 <std::array<int, 10ul>::operator[](unsigned long)>
arr2.operator[](6);
40056d: 48 8d 45 a0 lea -0x60(%rbp),%rax
400571: be 06 00 00 00 mov $0x6,%esi
400576: 48 89 c7 mov %rax,%rdi
400579: e8 08 00 00 00 callq 400586 <std::array<int, 10ul>::operator[](unsigned long)>
40057e: b8 00 00 00 00 mov $0x0,%eax
}
400583: c9 leaveq
400584: c3 retq
400585: 90 nop

What actually happens in C++ with function parameters?

I have been learning C++ for the past couple of months. I know with functions your first declare parameters like so:
int myFunc(int funcVar);
and then you can pass in an integer variable to that function like so:
int x = 5;
myFunc(x);
When passing an argument to a function I would usually think of it like assigning and copying the value of x into the parameter of myFunc, which in C++ would look like this:
funcVar = x;
However, I noticed when declaring functions which have parameters of references (or pointers):
int myFunc(int & funcVar);
that I can either pass in the variable x to myFunc:
myFunc(x);
which would look like (in my mind):
&funcVar = x;
or you can pass in an actual reference as the argument
int & rX = x;
myFunc(rX);
and the function would work as well which with my thinking would look like this statement in C++
int & funcVar = rX
which would not make sense assigning a reference to a reference. My question is then how does the compiler actually load in arguments in a function? Should I not think of it like assigning the value of the variable to the parameter of the function?
When you call a function, each parameter of the function is initialized (not assigned). The rules for this are the same as the rules for any other copy-initialization. So if you have
int myFunc(int funcVar);
int x = 5;
myFunc(x);
then funcVar is initialized as though by a statement like this:
int funcVar = x;
and if you have
int myFunc(int & funcVar);
myFunc(x);
int & rX = x;
myFunc(rX);
then funcVar is initialized (and not assigned) as though by statements like this:
int & funcVar = x;
int & funcVar = rX;
The initialization of a reference binds it to the object or function denoted by the initializer. The second initialization does make sense---the expression rX denotes the object x because rX is a reference bound to x. Therefore, initializing a reference with rX has the same effect as initializing a reference with x.
Let us make easy code and disassemble.
int by_value(int x) { return x; }
int by_reference(int &x) { return x; }
int by_pointer(int *x) { return *x; }
int main()
{
int x = 1;
by_value(x);
by_reference(x);
by_pointer(&x);
return 0;
}
$ g++ -g -O0 a.cpp ; objdump -dS a.out
In my environment (x86_64, g++ (SUSE Linux) 4.8.3 20140627), result is as following.
(full text is here http://ideone.com/Z5G8yz)
00000000004005dd <_Z8by_valuei>:
int by_value(int x) { return x; }
4005dd: 55 push %rbp
4005de: 48 89 e5 mov %rsp,%rbp
4005e1: 89 7d fc mov %edi,-0x4(%rbp)
4005e4: 8b 45 fc mov -0x4(%rbp),%eax
4005e7: 5d pop %rbp
4005e8: c3 retq
00000000004005e9 <_Z12by_referenceRi>:
int by_reference(int &x) { return x; }
4005e9: 55 push %rbp
4005ea: 48 89 e5 mov %rsp,%rbp
4005ed: 48 89 7d f8 mov %rdi,-0x8(%rbp)
4005f1: 48 8b 45 f8 mov -0x8(%rbp),%rax
4005f5: 8b 00 mov (%rax),%eax
4005f7: 5d pop %rbp
4005f8: c3 retq
00000000004005f9 <_Z10by_pointerPi>:
int by_pointer(int *x) { return *x; }
4005f9: 55 push %rbp
4005fa: 48 89 e5 mov %rsp,%rbp
4005fd: 48 89 7d f8 mov %rdi,-0x8(%rbp)
400601: 48 8b 45 f8 mov -0x8(%rbp),%rax
400605: 8b 00 mov (%rax),%eax
400607: 5d pop %rbp
400608: c3 retq
0000000000400609 <main>:
int main()
{
400609: 55 push %rbp
40060a: 48 89 e5 mov %rsp,%rbp
40060d: 48 83 ec 10 sub $0x10,%rsp
int x = 1;
400611: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
by_value(x);
400618: 8b 45 fc mov -0x4(%rbp),%eax
40061b: 89 c7 mov %eax,%edi
40061d: e8 bb ff ff ff callq 4005dd <_Z8by_valuei>
by_reference(x);
400622: 48 8d 45 fc lea -0x4(%rbp),%rax
400626: 48 89 c7 mov %rax,%rdi
400629: e8 bb ff ff ff callq 4005e9 <_Z12by_referenceRi>
by_pointer(&x);
40062e: 48 8d 45 fc lea -0x4(%rbp),%rax
400632: 48 89 c7 mov %rax,%rdi
400635: e8 bf ff ff ff callq 4005f9 <_Z10by_pointerPi>
return 0;
40063a: b8 00 00 00 00 mov $0x0,%eax
}
by_reference(x) is as same as by_pointer(&x) !
It makes perfect sense to assign a reference to another reference (when first defining it, i.e. at initialization), and that's what actually happens. A reference is just an alias, so when you assign a reference to another reference you are just saying that the first one aliases the one you assigned. Example
int x = 42;
int& rx = x;
int& ry = rx;
++ry;
std::cout << x; // displays 43
Live on Coliru

why boost::scoped_ptr is cleared in a singleton implementation

I implemented a simple singleton by using boost::scoped_ptr:
template <class T> class Singleton : public boost::noncopyable {
public:
static T& instance() {
boost::call_once(init, flag);
return *t;
}
static void init() {
t.reset(new T());
}
private:
static boost::scoped_ptr <T> t;
static boost::once_flag flag;
};
template <class T> boost::scoped_ptr<T> Singleton<T>::t(0);
template <class T> boost::once_flag Singleton<T>::flag = BOOST_ONCE_INIT;
Define a real singleton class:
class S : public Singleton<S> {
public:
void p() { printf("hello");}
};
Then I define a static variable in file S.cpp:
static volatile S &S_instance = S::instance();
in main.cpp:
int main()
{
S &ss = S::instance();
ss.p();
}
Run this program, an exception happened:
/usr/include/boost/smart_ptr/scoped_ptr.hpp:91: T& boost::scoped_ptr::operator*() const [with T = S]: Assertion `px != 0' failed
Tracing the code, I found the static s_instance.t is cleared once the code leaves the static initialization segment and after that all code referring to the S::instance will get NULL scoped_ptr. Does anybody know the reason?
[UPDATE]
I tried to put all static into one cpp file (S1.cpp):
template <class T> boost::scoped_ptr<T> Singleton<T>::t(0);
template <class T> boost::once_flag Singleton<T>::flag = BOOST_ONCE_INIT;
static S& s_ins = S::instance();
and debug it with GDB, it looks follow the order I wrote. any idea?
A possible reason is that the static template <class T> boost::scoped_ptr<T> Singleton<T>::t(0); is initialized after the static volatile S &S_instance = S::instance();, and thus it replaced with 0 the value previously stored in t. The order in which the static variables are constructed is only defined within a single compilation unit, and I guess in your case t can be instantiated inside main.cpp (or rather in both files at compilation time, and the linker will have to choose just one) while S resides in S.cpp. Just a guess though.
I'm pretty sure that it is undefined behavior due to undefined creation order of global variables. So, your S_instance first initialized, and then template <class T> boost::scoped_ptr<T> Singleton<T>::t(0)
Such a simple program can illustrate, what can happen when order is reversed:
#include <iostream>
std::string &getS();
std::string& t = getS();
std::string s("hello");
std::string &getS() {s = "world"; return s;}
int main()
{
std::cout << t;
}
Well, it crashes for me with g++ and prints hello with cl
Your program works correctly (when compiled as a single file) if you remove this line:
static volatile S &S_instance = S::instance();
OK. When built on my machine without your S_instance declaration:
0000000000400d86 <__static_initialization_and_destruction_0(int, int)>:
400d86: 55 push %rbp
400d87: 48 89 e5 mov %rsp,%rbp
400d8a: 48 83 ec 10 sub $0x10,%rsp
400d8e: 89 7d fc mov %edi,-0x4(%rbp)
400d91: 89 75 f8 mov %esi,-0x8(%rbp)
400d94: 83 7d fc 01 cmpl $0x1,-0x4(%rbp)
400d98: 75 43 jne 400ddd <__static_initialization_and_destruction_0(int, int)+0x57>
400d9a: 81 7d f8 ff ff 00 00 cmpl $0xffff,-0x8(%rbp)
400da1: 75 3a jne 400ddd <__static_initialization_and_destruction_0(int, int)+0x57>
400da3: b8 b8 40 40 00 mov $0x4040b8,%eax
400da8: 0f b6 00 movzbl (%rax),%eax
400dab: 84 c0 test %al,%al
400dad: 75 2e jne 400ddd <__static_initialization_and_destruction_0(int, int)+0x57>
400daf: b8 b8 40 40 00 mov $0x4040b8,%eax
400db4: c6 00 01 movb $0x1,(%rax)
400db7: be 00 00 00 00 mov $0x0,%esi
400dbc: bf b0 40 40 00 mov $0x4040b0,%edi
400dc1: e8 3c 05 00 00 callq 401302 <boost::scoped_ptr<S>::scoped_ptr(S*)>
400dc6: b8 da 13 40 00 mov $0x4013da,%eax
400dcb: ba 90 40 40 00 mov $0x404090,%edx
400dd0: be b0 40 40 00 mov $0x4040b0,%esi
400dd5: 48 89 c7 mov %rax,%rdi
400dd8: e8 8b fd ff ff callq 400b68 <__cxa_atexit#plt>
400ddd: c9 leaveq
400dde: c3 retq
When compiled with your S_instance declaration:
0000000000400d86 <__static_initialization_and_destruction_0(int, int)>:
400d86: 55 push %rbp
400d87: 48 89 e5 mov %rsp,%rbp
400d8a: 48 83 ec 10 sub $0x10,%rsp
400d8e: 89 7d fc mov %edi,-0x4(%rbp)
400d91: 89 75 f8 mov %esi,-0x8(%rbp)
400d94: 83 7d fc 01 cmpl $0x1,-0x4(%rbp)
400d98: 75 4f jne 400de9 <__static_initialization_and_destruction_0(int, int)+0x63>
400d9a: 81 7d f8 ff ff 00 00 cmpl $0xffff,-0x8(%rbp)
400da1: 75 46 jne 400de9 <__static_initialization_and_destruction_0(int, int)+0x63>
400da3: e8 c2 04 00 00 callq 40126a <Singleton<S>::instance()>
400da8: 48 89 05 01 33 00 00 mov %rax,0x3301(%rip) # 4040b0 <S_instance>
400daf: b8 c0 40 40 00 mov $0x4040c0,%eax
400db4: 0f b6 00 movzbl (%rax),%eax
400db7: 84 c0 test %al,%al
400db9: 75 2e jne 400de9 <__static_initialization_and_destruction_0(int, int)+0x63>
400dbb: b8 c0 40 40 00 mov $0x4040c0,%eax
400dc0: c6 00 01 movb $0x1,(%rax)
400dc3: be 00 00 00 00 mov $0x0,%esi
400dc8: bf b8 40 40 00 mov $0x4040b8,%edi
400dcd: e8 3c 05 00 00 callq 40130e <boost::scoped_ptr<S>::scoped_ptr(S*)>
400dd2: b8 e6 13 40 00 mov $0x4013e6,%eax
400dd7: ba 90 40 40 00 mov $0x404090,%edx
400ddc: be b8 40 40 00 mov $0x4040b8,%esi
400de1: 48 89 c7 mov %rax,%rdi
400de4: e8 7f fd ff ff callq 400b68 <__cxa_atexit#plt>
400de9: c9 leaveq
400dea: c3 retq
In the latter code, you can clearly see that the constructor for the static scoped_ptr happens after S_instance.
The above were compiled from:
#include <cstdio>
#include <boost/scoped_ptr.hpp>
#include <boost/thread/once.hpp>
#include <boost/noncopyable.hpp>
template <class T> class Singleton : public boost::noncopyable {
public:
static T& instance() {
boost::call_once(init, flag);
return *t;
}
static void init() {
t.reset(new T());
}
private:
static boost::scoped_ptr <T> t;
static boost::once_flag flag;
};
template <class T> boost::scoped_ptr<T> Singleton<T>::t(0);
template <class T> boost::once_flag Singleton<T>::flag = BOOST_ONCE_INIT;
class S : public Singleton<S> {
public:
void p() { printf("hello");}
};
// static volatile S &S_instance = S::instance();
int main()
{
S &ss = S::instance();
ss.p();
}
I think that this is wrong:
static volatile S &S_instance = S::instance();
because it creates and then deletes the instance. You want a pointer, not a reference.
static S *S_instance = &S::instance();
As far as I know the reference goes out of scope at the end of the .cpp file. The instance is not expected to ever be deleted anyway, so T can just be a bare pointer.