c++ - c++11 parameter pack wrong behaviour with Apple LLVM 7.0.0 but works with GCC-5.1 -
going previous version of question, @gene, able reproduce behaviour using simpler example.
#include <iostream> #include <vector> class wrapper { std::vector<int> const& bc; public: wrapper(std::vector<int> const& bc) : bc(bc) { } int getsize() const { return bc.size(); } }; class adapter { wrapper wrapper; public: adapter(wrapper&& w) : wrapper(w) { } int getsize() const { return wrapper.getsize(); } }; template <class t> class mixin : public adapter { public: //< replace "types ... args" "types& ... args" , works apple llvm template <class ... types> mixin(types ... args) : adapter(t(args...)) { } }; int main() { std::vector<int> data; data.push_back(5); data.push_back(42); mixin<std::vector<int>> mixin(data); std::cout << "data: " << data.size() << "\n"; std::cout << "mixin: " << mixin.getsize() << "\n"; return 0; }
result using apple llvm, tested -std=c++11
, -std=c++14
:
data: 2 mixin: -597183193
interestingly, i've tested code @ideone uses gcc-5.1 c++14 enabled, , works expected!
data: 2 mixin: 2
why mixin.getsize()
return garbage value on clang , why work gcc-5.1?
@gene suggested i'm using types ... args
creates temporary copy of vector (and using types& ... args
makes work llvm), copy contain same elements (thus have same size).
you have dangling reference, , mixin.getsize()
yielding undefined behavior:
- inside of
mixin
's constructor,t
=std::vector<int>
,adapter(t(args...))
passingadapter
's constructor temporarystd::vector<int>
adapter
's constructor parameterwrapper&&
, we're passingstd::vector<int>&&
, invokewrapper
's implicit conversion constructorwrapper
's constructor parameterstd::vector<int> const&
, , we're passingstd::vector<int>&&
; rvalues allowed bind const-lvalue references, syntactically fine , compiles fine, in effect we're bindingwrapper::bc
temporary- once construction finished, lifetime of temporary created in
mixin
's constructor ends, ,wrapper::bc
becomes dangling reference; callsadapter::getsize
yield ub
when mixin
's constructor parameters changed types...
types&...
, adapter(t(args...))
still passing adapter
's constructor temporary std::vector<int>
; appears work because seeing different manifestation of ub (likely stack looks bit different due 1 fewer copies of std::vector<int>
being made). i.e., both versions of code equally broken/wrong!
so, answer concretely:
why
mixin.getsize()
return garbage value on clang , why work gcc-5.1?
because behavior of undefined behavior undefined. ;-] appearing work 1 possible outcome, code still broken , appearance of being correct purely superficial.
Comments
Post a Comment