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...)) passing adapter's constructor temporary std::vector<int>
  • adapter's constructor parameter wrapper&&, we're passing std::vector<int>&&, invoke wrapper's implicit conversion constructor
  • wrapper's constructor parameter std::vector<int> const&, , we're passing std::vector<int>&&; rvalues allowed bind const-lvalue references, syntactically fine , compiles fine, in effect we're binding wrapper::bc temporary
  • once construction finished, lifetime of temporary created in mixin's constructor ends, , wrapper::bc becomes dangling reference; calls adapter::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

Popular posts from this blog

get url and add instance to a model with prefilled foreign key :django admin -

css - Make div keyboard-scrollable in jQuery Mobile? -

ruby on rails - Seeing duplicate requests handled with Unicorn -