https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61015
Melissa <myriachan at gmail dot com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |myriachan at gmail dot com --- Comment #1 from Melissa <myriachan at gmail dot com> --- Your code is doing something bad - it's retaining a pointer to a temporary object across a function call. Although pointers to a derived class are convertible to pointers to a parent class, that is not true for double-pointers. For example, the following code is not legal: struct Base {}; struct Derived : Base {}; int main() { // I don't normally use so-called Hungarian notation, but here it's clearer Derived *pDerived = new Derived(); Derived **ppDerived = &pDerived; // This is legal. Base *pBase = pDerived; // This is not legal, and will cause a compiler error. Base **ppBase = ppDerived; return 0; } So back to your code, the problem is visible in this small part: template<typename T> class ArrayRef { private: const T* data; ArrayRef( const T& oneElt ) // <--- important { this->data = &oneElt; ... } }; int main() { SpecialObj specialObj; SpecialObj* pSpecialObj = &specialObj; ArrayRef<Obj*> arrayRef( pSpecialObj ); ... } The important thing is the const T & parameter. T is Obj *, not SpecialObj *, so the constructor takes Obj *const &. (The const ends up on the right side of the asterisk in this notation when expanding out T.) References are really pointers in alternate syntax, and just like pointers, it is not legal to have a double-pointer conversion from derived to base. Just like how SpecialObj ** can't be assigned to type Obj *const *, it's also the case that SpecialObj * can't be bound to Obj *const &. But why does it compile when the double-pointer case didn't? It's because const references have another property: they also take temporaries. If an object cannot be bound as a const lvalue to the const reference, the compiler will instead try to create a temporary using an implicit conversion, constructor call, or similar, then bind the temporary to the const reference. Here, the temporary it can create is of type Obj *. And sure enough, SpecialObj * can be implicitly converted to Obj *. So the compiler is going to create a temporary Obj * on the stack containing a copy of the SpecialObj * cast to Obj *, then pass *that* to to the ArrayRef<T> constructor. Then you save a pointer to the passed const Obj * inside the ArrayRef<T> constructor. References are really just pointers behind the scenes - and you just saved a pointer to a temporary object. Now your ArrayRef class has a pointer to an arbitrary location in the caller's stack. I'm going to guess that the compilers that don't crash are actually not crashing because of the optimizer. The inlining of the optimizer may actually cause the temporary to remain in the current stack frame, possibly preventing the pointer from corrupting anything. It's when the pointer stored in ArrayRef<T> points to a temporary whose memory was freed and reused that you have a problem.