C++0x rvalue refs get clobbered somehow

Lukas Mai l.mai@web.de
Sat Mar 15 02:28:00 GMT 2008


Hello!

I'm having problems with g++-4.3.0 and C++0x. Disclaimer: I don't
understand rvalue references, but since I need (indirect) argument
forwarding, I copied and modified an example from the web.

Here's (a simplified version of) my code. Details like destructors,
dynamic memory management, etc are gone; it's just generic object
construction.

------------------------------------------------------------------
#include <cstdlib>
#include <iostream>

namespace awesome {

    namespace detail_region {
        template<typename T> struct Typedef { typedef T t; };
        template<typename T> T &&fw(typename Typedef<T>::t &&x) { return x; }

        template<typename ...> struct tuple;

        template<> struct tuple<> {
            template<typename T, typename ...Args> T *capply(void *place, Args 
&&...args) const {
                return new (place) T(fw<Args>(args) ...);
            }
        };

        template<typename Hd, typename ...Tl> struct tuple<Hd, Tl ...> {
            Hd &&head;
            tuple<Tl ...> tail;
            tuple(Hd &&h, Tl &&...t) : head(fw<Hd>(h)), tail(fw<Tl>(t) ...) {}

            template<typename T, typename ...Args> T *capply(void *place, Args 
&&...args) const {
                return tail.capply<T>(place, fw<Args>(args) ..., 
fw<Hd>(head));
            }
        };
    }

    struct region {
        private:
            template<typename ...Args> struct spork {
                detail_region::tuple<Args ...> args;

                spork(Args &&...x) : args(detail_region::fw<Args>(x) ...) {}

                template<typename T> operator T *() const {
                    // ::operator new(1);
                    // std::cout << "hi\n";
                    std::rand();  // XXX any function call here seems to cause 
problems

                    static char raw_[sizeof (T)];
                    return args.template capply<T>(raw_);
                }
            };

        public:

            template<typename ...Args> spork<Args ...> alloc(Args &&...args) {
                return spork<Args ...>(detail_region::fw<Args>(args) ...);
            }
    };
}


using namespace std;

int main() {
    using awesome::region;

    region r;
    int *p = r.alloc(123);
    cout << *p << '\n';
}
------------------------------------------------------------------

This code works fine (and prints 123) when compiled with
g++ -std=c++0x -O2 (or -Os or -O). However, without optimization
it produces output like -1207981096. This number changes if
different function calls are used at the location marked XXX.

Somehow args.head loses its value between construction (in alloc)
and use (in capply), but only if optimizations are not enabled.
This is obviously a bug, either in my code or in g++.

I think args.head should be bound to the temporary value 123,
which should stay alive until the next statement. But something
seems to overwrite it before p is initialized.

Can you explain to me what's going on here? How can I fix this
code? (And is this the right place to ask?)

Thanks in advance
Lukas



More information about the Gcc-help mailing list