Russian Qt Forum
Ноябрь 23, 2024, 18:24 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Стоит ли запрещать конструктор копирования и оператор присваивания?  (Прочитано 6167 раз)
Blackwanderer
Гость
« : Март 26, 2012, 16:50 »

Одна из рекомендаций в Google Code Style звучит следующим образом:
Код:
Provide a copy constructor and assignment operator only when necessary. Otherwise, disable them with DISALLOW_COPY_AND_ASSIGN.
Обоснование приводится следующее:
Код:
Implicit copying of objects in C++ is a rich source of bugs and of performance problems.
It also reduces readability, as it becomes hard to track which objects are being passed
around by value as opposed to by reference, and therefore where changes to an object are reflected.
Как вы считаете, действительно ли это стоящая рекомендация и следует её придерживаться, или это просто преверженность привычному C-стилю и страх перед новым, мол какая-то это новая неведамая фигня, давайте не будём её использовать?

И небольшой частный случай, привёдший к такому вопросу. Есть класс ConstMatrix (матрица, элементы которой нельзя изменять) и Matrix (просто матрица). Matrix наследует от ConstMatrix. Оба типа матриц нужно транспонировать. Результат транспонирования всегда будет ConstMatrix. Важно заметить, что сложность копирования матрицы при такой архитектуре стремится к O(1). Соответственно вижу два подхода к решению этой задачи:
  • Запрещаем конструктор копирования и присваивания
Код
C++ (Qt)
void ConstMatrix::transpose(ConstMatrix &transposed) const
{
// Проверяем в runtime действительно ли transposed - объект класса ConstMatrix, а не объект дочернего класса.
// Если это объект дочернего класса - получаем потенциальную проблему безопасности.
transposed=...
}
 
void someFunction(const Matrix &A)
{
ConstMatrix transposed;
A.transpose(transposed);
....
}
 
  • Разрешаем конструктор копирования и присваивания
Код
C++ (Qt)
ConstMatrix ConstMatrix::transposed() const
{
Const Matrix transposed;
...
return transposed;
}
 
void someFunction(const Matrix &A)
{
ConstMatrix transposed = A.transposed();
....
}
 

    Мне больше нравится второй вариант потому что
    1. Отсев ошибок на этапе компиляции предпочтительней отсева ошибок на этапе выполнения.
    2. Минимизируется время между объявлением и инициализацией переменной transposed
    3. Такой код легче читается, более понятен
    НО! Может быть есть какие-то подводные камни из-за разрешения присваивания/копирования (лично я-то ничего плохого/опасного в этом не вижу)?
    Записан
    Пантер
    Administrator
    Джедай : наставник для всех
    *****
    Offline Offline

    Сообщений: 5876


    Жаждущий знаний


    Просмотр профиля WWW
    « Ответ #1 : Март 26, 2012, 16:54 »

    Или реализовываешь свой вариант, или запрещаешь, чтобы не огрести проблем со сгенерированными компилятором.
    Записан

    1. Qt - Qt Development Frameworks; QT - QuickTime
    2. Не используйте в исходниках символы кириллицы!!!
    3. Пользуйтесь тегом code при оформлении сообщений.
    Igors
    Джедай : наставник для всех
    *******
    Offline Offline

    Сообщений: 11445


    Просмотр профиля
    « Ответ #2 : Март 26, 2012, 21:09 »

    Как вы считаете, действительно ли это стоящая рекомендация и следует её придерживаться, или это просто преверженность привычному C-стилю и страх перед новым, мол какая-то это новая неведамая фигня, давайте не будём её использовать?
    Мое мнение - безусловно стоящая рекомендация которой стоит придерживаться. Может быть та или иная "модернуха" которая выглядит заманчиво/элегантно, но после применения я лично часто убеждался что выигрыш не так уж велик, а вот ненужных раздумий выплывает много. Короче - действовать по классике никогда не плохо, на то она и классика.

    И небольшой частный случай, привёдший к такому вопросу. Есть класс ConstMatrix (матрица, элементы которой нельзя изменять) и Matrix (просто матрица). Matrix наследует от ConstMatrix. Оба типа матриц нужно транспонировать. Результат транспонирования всегда будет ConstMatrix. Важно заметить, что сложность копирования матрицы при такой архитектуре стремится к O(1). Соответственно вижу два подхода к решению этой задачи:
    Ну далее в приведенном Вами коде вы (борзо) возвращаете по значению, поэтому надо ставить вопрос раньше - хотите ли Вы возвращать по значению? Для простых структур это нормально, напр
    Код
    C++ (Qt)
    QRect R = ...
     
    Здесь глупо каждый раз возиться с QRect по ссылке/указателю. Но если Ваша Matrix - потенциально большие данные - то ну его нафиг тот модерн, тут "подальше положишь - поближе возьмешь". Как правило отслеживание "а не сделал ли я чего" займет куда больше времени и сил чем чуть более развесистый код

    Ну конечно об оптимизации компилятора все в курсе, об implicit sharing также, давайте не тратить на это время
    Записан
    Blackwanderer
    Гость
    « Ответ #3 : Март 27, 2012, 04:21 »

    Ну далее в приведенном Вами коде вы (борзо) возвращаете по значению, поэтому надо ставить вопрос раньше - хотите ли Вы возвращать по значению?
    Я же написал, что сложность копирования стремится к O(1). Матрица неизменяемая, поэтому Shallow Copy.
    Записан
    Igors
    Джедай : наставник для всех
    *******
    Offline Offline

    Сообщений: 11445


    Просмотр профиля
    « Ответ #4 : Март 27, 2012, 10:20 »

    Я же написал, что сложность копирования стремится к O(1). Матрица неизменяемая, поэтому Shallow Copy.
    Но Вы же не написали что зарядили в класс матрицы implicit sharing (само оно ниоткуда не возьмется). Если так то вопрос "исперчен" - действуйте в духе Qt, по существу Вы приняли решение раньше. 
    Записан
    Akon
    Гость
    « Ответ #5 : Март 27, 2012, 13:46 »

    А вот запрещаете ли вы явно конструктор копирования и оператор присваивания в классах, наследуемых от классов, где эти операции уже запрещенны?
    Код:
    class MyObject : public QObject
    {
        Q_OBJECT
        Q_DISABLE_COPY(MyObject)  // пишите это или влом?
    }

    Если не запрещаете, то конструктор копирования и оператор присваивания формально будут доступны, но пользоваться ими будет нельзя, т.к. они недоступны в базовом классе. Результат - compile-time error.

    В Qt для QObject-типов пендюрят везде Q_DISABLE_COPY.
    Записан
    Blackwanderer
    Гость
    « Ответ #6 : Март 27, 2012, 16:51 »

    А вот запрещаете ли вы явно конструктор копирования и оператор присваивания в классах, наследуемых от классов, где эти операции уже запрещенны?
    Ясен пень, что если запрещать, то везде надо Улыбающийся
    Записан
    Страниц: [1]   Вверх
      Печать  
     
    Перейти в:  


    Страница сгенерирована за 0.1 секунд. Запросов: 23.