Разберемся, в каком порядке выводятся сообщения на экран во втором случае gnu++11.
Сначала в main вызываются два конструктора по умолчанию: для imnotdumb1 и временного объекта dumb_array();.
Далее в main вызывается метод
dumb_array & operator=( dumb_array temp)
, в котором temp инициализируется посредством метода
dumb_array (dumb_array&& other)
, который перед выводом на экран сообщения operator=( dumb_array tmp) вызывает ещё один конструктор по умолчанию.
Итого 3 конструктора по умолчанию, один перемещения, один оператор присваивания.
MSVC вызывает первые два конструктора по умолчанию и применяет move elision к инициализации temp.
То есть весь пример сводится к такому коду
#include <iostream>
using namespace std;
struct Foo {
Foo() { cout << "default ctor\n"; }
Foo(Foo&& arg) { cout << "move ctor\n"; }
};
void foo(Foo arg) {
cout << "foo\n";
}
int main () {
foo(Foo());
return 0;
}
В c++ существуют обязательные (mandatory) и необязательные случаи copy/move elision,
https://en.cppreference.com/w/cpp/language/copy_elision.
Применение правила из примера
In the initialization of an object, when the source object is a nameless temporary and is of the same class type (ignoring cv-qualification) as the target object.
до c++17 было необязательным к реализации, на усмотрение разработчиков компилятора.
В Microsoft считают такое правило обязательным вне зависимости от флагов компиляции,
Mandatory copy/move elision in Visual Studio
The C++ standard requires copy or move elision when the returned value is initialized as part of the return statement (such as when a function with return type Foo returns return Foo()). The Microsoft Visual C++ compiler always performs copy and move elision for return statements where it is required to do so, regardless of the flags passed to the compiler. This behavior is unchanged.
До c++17
требовалось, чтобы соответствующий copy/move ctor в случае copy elision всё равно был доступен (cppreference, там же):
This is an optimization: even when it takes place and the copy/move (since C++11) constructor is not called, it still must be present and accessible (as if no optimization happened at all), otherwise the program is ill-formed