I recently discovered the difference between msvc and g ++ / clang ++ compilers, which are related to the behavior of RVO when a persistent object is returned. A simple example illustrating the difference:
#include <iostream>
class T
{
public:
T() { std::cout << "T::T()\n"; }
~T() { std::cout << "T::~T()\n"; }
T(const T &t) { std::cout << "T::T(const T&)\n"; }
T(T &&t) { std::cout << "T::T(T&&)\n"; }
T(const T &&t) { std::cout << "T::T(const T&&)\n"; }
};
const T getT()
{
T tmp;
return tmp;
}
int main()
{
T nonconst = getT();
}
In optimizations, both examples will only produce T () and ~ T () calls, expected due to RVO (which, incidentally, ignores the return type constant). But without them, the results are different.
clang ++ or g ++ with -fno-elide-constructorsall the rules:
T::T()
T::T(T&&)
T::~T()
T::T(const T&&)
T::~T()
T::~T()
msvc (2013) ignores the return type constant:
T::T()
T::T(T&&)
T::~T()
T::~T()
With a little modification:
const T getT()
{
const T tmp;
return tmp;
}
clang ++ or g ++ c -fno-elide-constructors, all as expected again:
T::T()
T::T(const T&&)
T::~T()
T::T(const T&&)
T::~T()
T::~T()
msvc (2013):
T::T()
T::T(const T&&)
T::~T()
T::~T()
, ( const tmp): , , T(const T &&t) = delete; g++/clang++ : use of deleted function ‘T::T(const T&&)’ msvc .
, - MSVC? ( )
: msvc , g++/clang++ do not.
#include <iostream>
class T
{
public:
T() { std::cout << "T::T()\n"; }
~T() { std::cout << "T::~T()\n"; }
T(const T &t) { std::cout << "T::T(const T&)\n"; }
T(T &&t) { std::cout << "T::T(T&&)\n"; }
T(const T &&t) = delete;
};
const T getT()
{
const T tmp;
return tmp;
}
int main()
{
T nonconst = getT();
}