C ++: Weird segmentation fault, связанный с константными указателями на объекты [duplicate]

defer является логическим атрибутом [HTML 4.01 spec] :

Некоторые атрибуты играют роль булевых переменных (например, атрибут selected для элемент OPTION). Их появление в начале тега элемента подразумевает, что значение атрибута «истинно». Их отсутствие подразумевает значение «false».

[...]

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

вместо:

Авторы должны знать, что многие пользовательские агенты распознают только минимизированную форму логических атрибутов а не в полной форме.

Однако, если вы используете XHTML, вам нужно использовать вторую форму, поскольку XHTML следует синтаксису XML, где атрибуты всегда должны иметь значение.

1846
задан Rann Lifshitz 26 May 2018 в 12:07
поделиться

7 ответов

Когда мне нужно объявить их самостоятельно?

Правило трех утверждает, что если вы объявляете какой-либо из конструкторов копии

  1. оператор присваивания копии
  2. destructor

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

  • независимо от управления ресурсами выполнялось в одной операции копирования, возможно, необходимо было выполнить в другой операции копирования, а
  • деструктор класса также будет участвовать в управлении ресурсом (обычно его освобождая). Классическим ресурсом для управления была память, поэтому все классы стандартной библиотеки, которые управляют памятью (например, контейнеры STL, которые выполняют управление динамической памятью), объявляют «большую тройку»: обе операции копирования и деструктор.

Следствием правила трех является то, что присутствие объявленного пользователем деструктора указывает на то, что простая копия элемента с несколькими членами вряд ли будет подходящей для операций копирования в классе. Это, в свою очередь, предполагает, что если класс объявляет деструктор, операции копирования, вероятно, не должны автоматически генерироваться, потому что они не будут поступать правильно. В то время, когда C ++ 98 был принят, значение этой линии рассуждений не было полностью оценено, поэтому в C ++ 98 существование объявленного пользователем деструктора не повлияло на готовность компиляторов генерировать операции копирования. Это все еще имеет место в C ++ 11, но только потому, что ограничение условий, при которых выполняются операции копирования, приведет к сломанию слишком большого количества устаревшего кода.

Как я могу предотвратить, чтобы мои объекты не были скопировано?

Объявить конструктор копирования & amp; оператор присваивания копии в качестве спецификатора частного доступа.

class MemoryBlock
{
public:

//code here

private:
MemoryBlock(const MemoryBlock& other)
{
   cout<<"copy constructor"<<endl;
}

// Copy assignment operator.
MemoryBlock& operator=(const MemoryBlock& other)
{
 return *this;
}
};

int main()
{
   MemoryBlock a;
   MemoryBlock b(a);
}

В C ++ 11 вы также можете объявить конструктор копирования & amp; оператор присваивания удален

class MemoryBlock
{
public:
MemoryBlock(const MemoryBlock& other) = delete

// Copy assignment operator.
MemoryBlock& operator=(const MemoryBlock& other) =delete
};


int main()
{
   MemoryBlock a;
   MemoryBlock b(a);
}
19
ответ дан Ajay yadav 16 August 2018 в 00:32
поделиться

Правило of Three является правилом для C ++, в основном говоря

Если вашему классу требуется любой из

  • конструктор копирования,
  • оператор присваивания,
  • или деструктор,

определенно, тогда, вероятно, все три из них .

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

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

(Обратите внимание, что предстоящая новая версия стандарта C ++ (которая является C ++ 11) добавляет семантику перемещения в C ++, что, скорее всего, изменит правило из трех. Однако я слишком мало знаю об этом напишите раздел C ++ 11 о правиле трех.)

451
ответ дан Community 16 August 2018 в 00:32
поделиться
  • 1
    Другим решением для предотвращения копирования является наследование (конфиденциально) из класса, который нельзя скопировать (например, boost::noncopyable). Это также может быть намного яснее. Я думаю, что C ++ 0x и возможность «удалить» функции могут помочь здесь, но забыл синтаксис: / – Matthieu M. 13 November 2010 в 17:33
  • 2
    @Matthieu: Да, это тоже работает. Но если noncopyable не является частью std lib, я не считаю это существенным улучшением. (О, и если вы забыли синтаксис удаления, вы забыли mor ethan, который я когда-либо знал. :)) – sbi 13 November 2010 в 18:20
  • 3
    Любые обновления по правилу Three и C ++ 1x? – Daan Timmer 30 August 2013 в 08:28
  • 4
    @Daan: см. этот ответ . Тем не менее, я бы рекомендовал придерживаться Martinho Правило нуля . Для меня это один из самых важных правил для C ++, созданных в последнее десятилетие. – sbi 4 June 2014 в 18:46
  • 5
    Правило Зеленого Мартиньо теперь находится здесь – Diego 4 June 2015 в 18:14
27
ответ дан David Szalai 16 August 2018 в 00:32
поделиться

Закон большой тройки такой, как указано выше.

Легкий пример на простом английском языке той проблемы, которую он решает:

Неисправный деструктор

]

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

Вы можете подумать, что это работа.

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

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

Поэтому вы пишете конструктор копирования, чтобы он выделяет новые объекты для уничтожения своих собственных фрагментов памяти.

Оператор присваивания и конструктор копирования

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

Это означает, что новый объект и старый объект будут указывать на тот же кусок памяти, поэтому, когда вы меняете его на один объект, он будет изменен и для другого объекта objerct. Если один объект удаляет эту память, другой будет продолжать пытаться ее использовать - eek.

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

134
ответ дан rmobis 16 August 2018 в 00:32
поделиться
  • 1
    Поэтому, если мы используем конструктор копирования, тогда копия выполняется, но в другом месте памяти, и если мы не используем конструктор копирования, тогда выполняется копирование, но оно указывает на то же место в памяти. это то, что вы пытаетесь сказать? Таким образом, копия без конструктора копий означает, что новый указатель будет там, но указывая на одно и то же место памяти, однако, если у нас есть конструктор, явно определенный пользователем, тогда у нас будет отдельный указатель, указывающий на другую ячейку памяти, но имеющую данные. – Unbreakable 4 January 2015 в 15:01
  • 2
    Извините, я ответил на это много лет назад, но мой ответ, похоже, все еще не здесь :-( В принципе, да - вы его получите :-) – Stefan 27 July 2016 в 13:35
  • 3
    Как принцип ссылается на оператор присваивания копии? Этот ответ был бы более полезен, если бы упоминалось 3-е из 3-го правила. – DBedrenko 31 October 2017 в 18:44
  • 4
    @DBedrenko, "вы пишете конструктор копирования, чтобы он выделял новые объекты в свои собственные части памяти ... & quot; это тот же принцип, который распространяется на оператор присваивания копии. Разве вы не думаете, что я сделал это ясно? – Stefan 2 November 2017 в 10:07
  • 5
    @Stefan Да, спасибо большое! – DBedrenko 2 November 2017 в 13:14

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

    MyClass x(a, b);
    MyClass y(c, d);
    x = y; // This is a shallow copy if assignment operator is not provided

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

37
ответ дан Shakti Malik 16 August 2018 в 00:32
поделиться

Правило из трех в C ++ является основополагающим принципом проектирования и разработки трех требований, которые, если в одной из следующих функций-членов есть четкое определение, тогда программист должен определить две другие функции-члены вместе. А именно, необходимы следующие три функции-члена: деструктор, конструктор копирования, оператор присваивания копии.

Конструктор копирования в C ++ является специальным конструктором. Он используется для создания нового объекта, который является новым объектом, эквивалентным копии существующего объекта.

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

Быстрые примеры:

// default constructor
My_Class a;

// copy constructor
My_Class b(a);

// copy constructor
My_Class c = a;

// copy assignment operator
b = a;
5
ответ дан User that is not a user 16 August 2018 в 00:32
поделиться
  • 1
    Привет, ваш ответ не добавляет ничего нового. Остальные охватывают предмет гораздо глубже, а точнее - ваш ответ является приблизительным и на самом деле неправильным в некоторых местах (а именно, здесь нет «обязательно», «очень вероятно, должен»). На самом деле вам не стоило бы публиковать такой ответ на вопросы, на которые уже был дан ответ. Если у вас нет новых вещей для добавления. – Mat 15 August 2014 в 17:26
  • 2
    Кроме того, существуют быстрые примеры four , которые somehow связаны с двумя three , что правило трех говорит. Слишком много путаницы. – anatolyg 3 November 2014 в 16:41

Многие уже существующие ответы уже касаются конструктора копирования, оператора присваивания и деструктора. Тем не менее, в post C ++ 11 введение семантики перемещения может расширить это за пределы 3.

Недавно Майкл Клайс произнес разговор, затрагивающий эту тему: http://channel9.msdn.com / события / CPP / CPP-Con-2014 / The-Canonical класса

9
ответ дан wei 16 August 2018 в 00:32
поделиться