Гарантированное исключение копирования для инициализации однородного массива в фигурных скобках - разве это не должно быть обязательным, начиная с C ++ 17? [дубликат]

Dec 06 2020

Насколько я правильно понимаю новые правила

https://en.cppreference.com/w/cpp/language/copy_elision

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html

Этот код должен компилироваться для компиляторов, соответствующих стандарту C ++ 17.

struct NonTrivialClass
{
    ~NonTrivialClass( ){  }
};

class MainNonTrivialClass 
{
public:
  MainNonTrivialClass(int t) : m_simpleTypeMember(t) { }
 
  virtual void makeMySelfNonTrivial() {}

  MainNonTrivialClass( const MainNonTrivialClass& other) = delete;
  MainNonTrivialClass& operator=( const MainNonTrivialClass& other) = delete;
  MainNonTrivialClass(MainNonTrivialClass&& other) = delete;
  MainNonTrivialClass& operator=(MainNonTrivialClass&& other) = delete;
  
  NonTrivialClass m_nontrivialMember;
  int m_simpleTypeMember;
};

class ArrayContainer
{
public:
  ArrayContainer() : m_array{{1}, {2} } {}

private:
  MainNonTrivialClass m_array[2];
};


int main()
{
  ArrayContainer accContainer;
}

Но gcc 9.1.0 с -std = c ++ 17 -O2 -Wall -pedantic говорит (как и ожидалось до C ++ 17)

main.cpp: In constructor 'ArrayContainer::ArrayContainer()':
main.cpp:25:39: error: use of deleted function 'MainNonTrivialClass::MainNonTrivialClass(MainNonTrivialClass&&)'
   25 |   ArrayContainer() : m_array{{1}, {2} } {}
      |                                       ^
main.cpp:15:3: note: declared here
   15 |   MainNonTrivialClass(MainNonTrivialClass&& other) = delete;

Таким образом, унифицированная инициализация массива определяется как поэлементная инициализация копирования (?) И должна приводить к исключению копирования, поэтому я не совсем понимаю, что на самом деле здесь происходит. Похоже, здесь применяются старые правила, существовавшие до C ++ 17. Еще одно любопытство заключается в том, что тот же код компилируется нормально, если я удаляю m_nontrivialMember из своего MainNonTrivialClass, но не должно ли это приводить к той же ошибке компиляции, тогда всегда, поскольку случай отсутствия копирования-исключения всегда вызывает существование соответствующих конструкторов копирования / перемещения ?

Ответы

1 ecatmur Dec 06 2020 at 18:22

Это также должно работать до C ++ 17, где этот синтаксис является прямой инициализацией. См. Как инициализировать массив классов с помощью удаленного конструктора копирования (C ++ 11), который относится к ошибке GCC 63707 .