-1

When I declare a basic struct like this in Visual Studio 2019:

struct Test
{
    Test(Test &&test) = default;
};

the following assert fails :

static_assert(std::is_trivially_copyable<Test>::value, "Test is not trivially copyable !");

this one:

struct Test
{
    Test(const Test &test) = default;
};

or this one :

struct Test
{

};

obviously work. But I really don't understand what is happening with the first one. What is the difference between this one and the others in term of copying behavior?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Al227
  • 151
  • 7
  • 1
    https://stackoverflow.com/a/30097049/560648 – Lightness Races in Orbit Aug 24 '19 at 15:21
  • "*What is the difference between this one and the others?*" I'm not sure I understand what you're saying here. The difference is that one is a copy constructor and the other is a move constructor. Are you asking why they behave so significantly differently? – Nicol Bolas Aug 24 '19 at 15:26
  • Yes i want to know why the static_assert testing if the struct is trivially copyable works for the second and third struct, but not the first one. Because they all are trivially copyable for me – Al227 Aug 24 '19 at 15:26
  • 2
    Please analyze my question deeper instead of providing those answers. I want an explanation as to why the first one is not trivially copyable. – Al227 Aug 24 '19 at 15:30
  • And what version of C++/compiler are you using? That can affect the answer, as the rules of Trivial Copyability have changed over time. – Nicol Bolas Aug 24 '19 at 15:32
  • @Romain227: Then put that in the question, please. – Nicol Bolas Aug 24 '19 at 15:32
  • 5
    Seems to be a bug of VS. Can't reproduce with [gcc](https://wandbox.org/permlink/rd8k9g0foWWk6Ld1) and [clang](https://wandbox.org/permlink/3FcxwUGoVAw7u8ZG). – songyuanyao Aug 24 '19 at 15:37
  • @Lightness : "A trivially copyable class is a class that: has no non-trivial copy constructors, has no non-trivial move constructors, has no non-trivial copy assignment operators, has no non-trivial move assignment operators, and has a trivial destructor.". I think my first struct completely satisfies this – Al227 Aug 24 '19 at 15:40
  • @songyuanao : ok so it definitely seems like a VS bug indeed. Very strange though (and kinda scary tbh) – Al227 Aug 24 '19 at 15:41
  • @Romain227: It actually doesn't satisfy that constraint, but the [*actual* constraint is different](https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable). – Nicol Bolas Aug 24 '19 at 15:41

1 Answers1

2

This is a bug in Visual Studio for modern versions of C++, but it technically isn't a bug for the original release of C++11.

First, when I refer to Test, I am talking about your first definition. So that we're clear.

By explicitly defaulting Test's move constructor, you have caused the compiler to implicitly delete the copy constructor and assignment operator, unless you explicitly specify otherwise. The thinking behind this rule is that, if you went out of your way to explicitly default a constructor, you are probably trying to say something with that.

A type with only a defaulted move constructor looks like a move-only type, so the standard assumes that this is what you want. And if you don't want that, then you need to spell it out.

This doesn't happen for the copy constructor because move is considered a specialized form of copy. If a type is default copyable, it is logically default moveable, so leaving the move constructor implicitly defaulted makes sense.

Things like this are why you shouldn't default a special member function unless you either know how that will affect the others or you intend to default/delete/implement all of them.

In the initial release of C++11, the implicit deletion of copying for a defaulted move constructor would have made Test non-TriviallyCopyable. However, the wording for Trivial Copyability was changed around C++14 via a defect report. The new wording allowed a type to be TriviallyCopyable even if some of the copy/move constructors/assignment operators are deleted. Thus making Test TriviallyCopyable. Defect fixes usually apply retroactively, so technically a modern C++11 implementation should work too.

Visual Studio was never changed to fit the new wording. Hence the bug.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • "By explicitly defaulting Test's move constructor, you have caused the compiler to implicitly delete the copy constructor and assignment operator, unless you explicitly specify otherwise". Adding a defaulted copy construtor in addition to the defaulted move constructor still makes the assertion fail. – Al227 Aug 25 '19 at 07:34
  • @Romain227: I said, and you even copied me, "and assignment operator". Or more specifically, "Things like this are why you shouldn't default a special member function unless you either know how that will affect the others or you intend to default/delete/implement all of them." – Nicol Bolas Aug 25 '19 at 13:25