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::bctemporary- once construction finished, lifetime of temporary created in
mixin's constructor ends, ,wrapper::bcbecomes dangling reference; callsadapter::getsizeyield 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