На конструктор по умолчанию для нельзя ссылаться так как эта функция удалена

Обновлено: 05.05.2024

У меня есть очень простая структура, в которой есть перечисление и объединение.

При использовании такой структуры я получаю код ошибки C2280, что на конструктор по умолчанию нельзя ссылаться. Когда я объявляю структуру немного по-другому, как показано ниже

Ошибка больше не существует. Я не могу понять причину этого. Кто-нибудь может объяснить, почему это происходит

Примечание: обратите внимание на std::any и std::variant . Последний обеспечивает типобезопасные союзы и, вероятно, будет лучшим выбором в вашем случае. Обратите внимание, что ваш компилятор (очевидно, MSVC) должен поддерживать C++17.

Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату.

Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно.

Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей.

Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.

У каждого из нас бывали случаи, когда нам нужно отцентрировать блочный элемент, но мы не знаем, как это сделать. Даже если мы реализуем какой-то.

Ответы 3

В первом примере вы определяете переменную-член, которая должна быть конструируемой по умолчанию. Во втором примере вы определяете элемент тип, который выдаст ту же ошибку, если вы используете его для определения переменной этого типа.

Что касается ошибки, вам нужно создать конструктор по умолчанию в объединении, чтобы иметь возможность правильно его инициализировать:

@ Какой-то программист, чувак. Даже после использования кода, который вы предоставили, я все равно получаю ту же ошибку.

@eeorika Инициализатор члена по умолчанию также не решает проблему.

Some programmer dude

Проблема в том, что объединение w не является ни конструируемым по умолчанию, ни разрушаемым. Конструктор по умолчанию и деструктор не генерируются неявно, потому что член c не является тривиально конструируемым или разрушаемым. Таким образом, наличие члена типа w просто невозможно. Во втором примере вы удаляете участника, так что проблем нет.

Чтобы сделать w по умолчанию конструктивным, вы можете определить конструктор по умолчанию:

Чтобы сделать w разрушаемым, вы можете определить деструктор (но читайте до конца):

Советы по уничтожению активного члена:

  • Невозможно узнать, какой член активен.
  • Доступ к неактивному члену имеет неопределенное поведение
  • Если c активен, неразрушающий его имеет неопределенное поведение

В заключение: вы должны убедиться, что w никогда не уничтожается, пока активен участник c . Такой инвариант может быть реализован в деструкторе Data_Set2 , предполагая, что v указывает, какой элемент является активным (это еще один инвариант, который следует поддерживать; эти элементы, вероятно, не должны быть общедоступными).

If a union contains a non-static data member with a non-trivial special member function (copy/move constructor, copy/move assignment, or destructor), that function is deleted by default in the union and needs to be defined explicitly by the programmer.

If a union contains a non-static data member with a non-trivial default constructor, the default constructor of the union is deleted by default unless a variant member of the union has a default member initializer .

At most one variant member can have a default member initializer.

В вашем случае это означает, что вы должны явно объявить конструктор и деструктор. Измените свой код на:

Это должно работать.

Как уже говорилось в моем комментарии, вам следует взглянуть на std::any и std::variant . Последний обеспечивает типобезопасные союзы и, вероятно, будет лучшим выбором в вашем случае. Обратите внимание, что ваш компилятор (очевидно, MSVC) должен поддерживать C++17.

Обновлено: Как прокомментировал eeorika, вам нужно убедиться, что вы вызываете его только для текущего активного члена. Справочник, указанный в начале, показывает пример для объединения строки/вектора и того, как он вводит множество ловушек для неопределенного поведения. Поэтому, если вы просто не пытаетесь понять, что происходит за кулисами или используете типы POD, я бы посоветовал вам вместо этого работать с std::variant .

Что касается «Это должно работать»: что происходит, когда c активен, когда объект уничтожается?

@eerorika: О, это правда. Я предполагаю, что вам придется явно вызывать деструктор члена, но я не уверен, поэтому я бы не стал обновлять свой ответ. Предполагая, что у вас есть Data_Set2 x; , я бы предположил, что вам нужно вызвать x.c.~basic_string(); (?). Я постараюсь провести дополнительные исследования по этому поводу.

Я думаю, что ответ таков: деструктор Data_Set2 должен убедиться, что w.c никогда не активируется после уничтожения.

У меня есть очень базовая структура, в которой есть enum и union.

При использовании такой структуры я получаю код ошибки C2280, что на конструктор по умолчанию нельзя ссылаться. Когда я объявляю структуру немного по-другому, как показано ниже

Ошибка больше не существует. Я не понимаю причину этого. Может ли кто-нибудь объяснить, почему это происходит

3 ответа

Если объединение содержит нестатический член данных с нетривиальной специальной функцией-членом (конструктор копирования / перемещения, назначение копирования / перемещения или деструктор), эта функция удаляется по умолчанию в объединении и должна быть явно определена программист.

Если объединение содержит нестатический член данных с нетривиальным конструктором по умолчанию, конструктор объединения по умолчанию удаляется по умолчанию, если только вариантный член объединения не имеет инициализатора элемента по умолчанию.

Не более одного варианта элемента может иметь инициализатор элемента по умолчанию.

В вашем случае это означает, что вы должны явно объявить конструктор и деструктор. Измените свой код на:

Это должно работать.

Как уже говорилось в моем комментарии, вы должны взглянуть на std::any и std::variant . Последний обеспечивает типобезопасные союзы и, вероятно, будет лучшим выбором в вашем случае. Обратите внимание, что ваш компилятор (очевидно, MSVC) должен поддерживать C ++ 17.

РЕДАКТИРОВАТЬ: Как прокомментировал eerorika, вы должны быть уверены, что вы вызываете его только на активного участника. Ссылка, указанная в начале, показывает пример объединения строк и векторов и того, как она вводит много ловушек для неопределенного поведения. Поэтому, если вы просто не пытаетесь понять, что происходит за кулисами или используете типы POD, я бы посоветовал вам работать с std::variant .

В первом примере вы определяете переменную-член, которая должна быть конструируемой по умолчанию. Во втором примере вы определяете член тип , который выдаст ту же ошибку, если вы используете его для определения переменной этого типа.

Что касается ошибки, вам нужно создать конструктор по умолчанию в объединении, чтобы иметь возможность правильно его инициализировать:

Проблема в том, что объединение w не является ни конструируемым по умолчанию, ни разрушаемым. Конструктор по умолчанию и деструктор не генерируются неявно, потому что член c не является ни тривиально, ни тривиально разрушаемым. Таким образом, наличие члена типа w просто невозможно. Во втором примере вы удаляете участника, поэтому проблем нет.

Чтобы сделать w конструируемым по умолчанию, вы можете определить конструктор по умолчанию:

Чтобы сделать w разрушаемым, вы можете определить деструктор (но читайте до конца):

Советы по уничтожению активного члена:

  • Невозможно выяснить, какой участник активен.
  • Доступ к неактивному члену имеет неопределенное поведение
  • Если c активен, не уничтожая его имеет неопределенное поведение

В заключение: вы должны убедиться, что w никогда не будет уничтожен при активном участнике c . Такой инвариант может быть реализован в деструкторе Data_Set2 , предполагая, что v указывает, какой элемент является активным (который является другим инвариантом, который следует поддерживать; эти члены, вероятно, не должны быть открытыми).

Компилятор обнаружил попытку сослаться deleted на функцию. Эта ошибка может быть вызвана вызовом функции-члена, которая явно помечена как = deleted в исходном коде. Эта ошибка также может быть вызвана вызовом неявной специальной функции-члена структуры или класса, которая автоматически объявляется и помечается как deleted компилятор. Дополнительные сведения о том, когда компилятор автоматически создает default или deleted специальные функции элементов, см. в разделе специальные функции элементов.

Пример. явно удаленные функции

Вызов явной deleted функции вызывает эту ошибку. Явная deleted функция-член предполагает, что класс или структура преднамеренно спроектирована для предотвращения его использования, поэтому для устранения этой проблемы следует изменить код, чтобы избежать этого.

Пример: неинициализированные члены данных

Неинициализированный член данных ссылочного типа или const член данных приводит к тому, что компилятор неявно объявляет deleted конструктор по умолчанию. Чтобы устранить эту проблему, инициализируйте член данных при его объявлении.

Пример: ссылочные и константные элементы данных

const Член данных ссылочного типа или указывает компилятору объявить deleted оператор присваивания копии. После инициализации эти члены не могут быть назначены, поэтому простое копирование или перемещение не может работать. Чтобы устранить эту проблему, мы рекомендуем изменить логику, чтобы удалить операции назначения, которые вызывают ошибку.

Пример: перемещаемый удаляет неявную копию

Если класс объявляет конструктор перемещения или оператор присваивания перемещения, но не объявляет конструктор копии явным образом, компилятор неявно объявляет конструктор копии и определяет его как deleted . Аналогично, если класс объявляет конструктор перемещения или оператор присваивания перемещения, но явно не объявляет оператор присваивания копирования, компилятор неявно объявляет оператор присваивания копирования и определяет его как deleted . Чтобы устранить эту проблему, необходимо явно объявить эти члены.

При появлении ошибки C2280 в соединении с unique_ptr , это почти наверняка обусловлено тем, что вы пытаетесь вызвать конструктор копии, который является deleted функцией. Не может быть скопировано по дизайну unique_ptr . Используйте конструктор Move, чтобы вместо этого передавать владение.

Пример: элементы типа Variant и volatile

версии компилятора до Visual Studio 2015 с обновлением 2 были не согласованы и созданы конструкторы и деструкторы по умолчанию для анонимных объединений. Теперь они неявно объявляются как deleted . Эти версии также позволяли неявное определение default конструкторов копирования и перемещения, а default также операторы копирования и перемещения в классах и структурах, имеющих volatile переменные-члены. Компилятор рассматривает их как нетривиальные конструкторы и операторы присваивания, а также не создает default реализации. Если такой класс является членом объединения или анонимным объединением внутри класса, конструкторы копирования и перемещения, а также операторы копирования и перемещения Union или класса неявно определяются как deleted . Чтобы устранить эту проблему, необходимо явно объявить необходимые специальные функции элементов.

Пример: удаленные непрямые базовые члены

версии компилятора до Visual Studio 2015 с обновлением 2 не были согласованы и позволял производному классу вызывать специальные функции-члены косвенно производных private virtual базовых классов. Компилятор теперь выдает ошибку компилятора C2280, когда выполняется такой вызов.

В этом примере класс top косвенно является производным от частного виртуального base . В результате выполнения кода это делает элементы base недоступными для top ; объект типа top не может быть создан или удален по умолчанию. Чтобы устранить эту проблему в коде, который основан на старом поведении компилятора, измените промежуточный класс на использование protected virtual наследования или измените top класс для использования прямого наследования:

TL; DR: вы получаете бесплатно конструктор по умолчанию, только если вы сами не определяете конструктор. Отвечает ли это на ваш вопрос? Есть ли в C ++ неявный конструктор по умолчанию?

Я так не думаю, решение, которого я хочу достичь, - это иметь конструктор в структуре Book, но не использовать его в структуре list_of_books. Я думаю, что ошибка возникает из-за того, что структура списка наследует конструктор от структуры Book, но я его не использую. Поэтому мне нужно как-то использовать структуру Book в структуре list_of_books без использования конструктора книги.

вы используете его, у struct list_of_books него есть член, struct Book book; и вы пытаетесь создать его через list_of_books* element = new list_of_books; . Как вы хотите создать участника book при создании list_of_books ?

этот конструктор вреден. У вас есть агрегат - тип, который является его данными - и конструктор, который просто повторяет элементы по порядку.

и повторите для каждого написанного вами конструктора.

Конструкторы, которые ничего не делают, кроме как повторяют аргументы по порядку, - нехорошие вещи.

Если вы удалите все конструкторы в своей программе, ваша программа будет компилироваться.

Что теперь не так? Создавая конструктор, вы удаляете конструктор без аргументов по умолчанию.

Затем, когда вы new list_of_books , он пытается использовать конструктор для Book , которого не существует.

Обратите внимание, что при работе с агрегатами вы должны использовать <> списки конструирования фигурных скобок, если вы хотите создавать их на месте, например Book b = ; , вместо () аргументов.

Ой, хорошо, я не знал, что мне не следует создавать этот тип конструкторов, и я даже не знал об этом типе объявления Book b = <. >. Это очень помогает. Я создал конструкторы, потому что мне нужно читать данные из файла .txt, и я не могу их использовать, getline() потому что я сохраняю их для различных типов структурных переменных, и я подумал, что конструкторы мне помогут. Большое спасибо за ответ.

@booboo также делают и int day=0; т. д .; эти ctors могут быть полезны, но если вы добавите их, ctor по умолчанию будет удален.

Я работал над некоторым кодом C++, который написал друг, и я получаю следующую ошибку, которую я никогда раньше не видел при компиляции с помощью gcc4.6:

Изменить: это происходит из части кода, использующего boost MSM: веб- страница Boost

Edit2: = delete() нигде в исходном коде не используется.

Вообще говоря, что означает эта ошибка? Что я должен искать, когда возникает этот тип ошибки?


Поскольку это первое совпадение Google для этого типа ошибки - здесь не тот случай, но наиболее частая причина такого рода ошибок - после того, как вы добавили какой-то пользовательский конструктор в класс - в результате компилятор перестает создавать конструктор по умолчанию , и если экземпляр класса когда-либо создается с помощью конструктора по умолчанию, появляется эта ошибка. Просто явно добавьте конструктор по умолчанию.

Поскольку X::x is const , он должен быть инициализирован, но ctor по умолчанию обычно не инициализирует его (потому что это тип POD). Следовательно, чтобы получить ctor по умолчанию, вам нужно определить его самостоятельно (и он должен инициализироваться x ). Вы можете получить такую ​​​​же ситуацию с членом, который является ссылкой:

Вероятно, стоит отметить, что оба они также отключают неявное создание оператора присваивания, по сути, по той же причине. Неявный оператор присваивания обычно выполняет присваивание по членам, но с константным членом или ссылочным элементом он не может этого сделать, потому что член не может быть назначен. Чтобы присваивание работало, вам нужно написать свой собственный оператор присваивания.

Вот почему const член обычно должен быть статическим — когда вы выполняете присваивание, вы все равно не можете присвоить константный член. В типичном случае все ваши экземпляры будут иметь одинаковое значение, поэтому они могут также иметь общий доступ к одной переменной вместо того, чтобы иметь множество копий переменной, которые все будут иметь одинаковое значение.

Конечно, можно создавать экземпляры с разными значениями — вы (например) передаете значение при создании объекта, поэтому два разных объекта могут иметь два разных значения. Если, однако, вы попытаетесь сделать что-то вроде замены их местами, элемент const сохранит свое исходное значение, а не будет заменен.

Читайте также: