Перегрузка оператора с выделением памяти?

Приведенное ниже предложение взято из Положительное наследие C++ и Java Брюса Экеля, о перегрузке операторов в C++:

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

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


person yesraaj    schedule 25.03.2009    source источник
comment
Я не работал с С++. Но если вы перегрузите оператор, может потребоваться возврат нового значения (которое может быть в стеке для простых значений и в куче для сложных типов), например. Лицо* а; человек* б; Человек* c = a + b;   -  person shahkalpeshp    schedule 25.03.2009


Ответы (4)


Я могу представить пару возможных интерпретаций:

Во-первых, в C++ new и delete на самом деле являются операторами; если вы решите обеспечить настраиваемое поведение выделения для объекта, перегружая эти операторы, вы должны быть очень осторожны при этом, чтобы убедиться, что вы не создаете утечки.

Во-вторых, некоторые типы объектов требуют перегрузки operator=, чтобы избежать ошибок управления памятью. Например, если у вас есть объект интеллектуального указателя с подсчетом ссылок (например, Boost shared_ptr), вы должны реализовать operator= и сделать это правильно. Рассмотрим этот сломанный пример:

template <class T>
class RefCountedPtr {
public:
    RefCountedPtr(T *data) : mData(data) { mData->incrRefCount(); }
    ~RefCountedPtr() { mData->decrRefCount(); }
    RefCountedPtr<T>& operator=(const RefCountedPtr<T>& other) {
        mData = other.mData;
        return *this;
    }
    ...
protected:
    T *mData;
};

Реализация operator= здесь нарушена, потому что она не управляет счетчиками ссылок на mData и other.mData: она не уменьшает счетчик ссылок на mData, что приводит к утечке; и он не увеличивает счетчик ссылок на other.mData, что приводит к возможному сбою памяти в будущем, потому что объект, на который указывает указатель, может быть удален до того, как все фактические ссылки исчезнут.

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

Итак, как говорится в статье, в некоторых случаях вы должны перегружать операторы, и вы должны быть осторожны, чтобы правильно обрабатывать все ситуации.

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

person Eric Melski    schedule 25.03.2009
comment
это статья... просто нажмите на ссылку - person yesraaj; 25.03.2009
comment
Однако в статье не было большого контекста - я подозреваю, что Эрик говорил о книге, упомянутой в статье. - person 1800 INFORMATION; 25.03.2009

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

person Naveen    schedule 25.03.2009

Операторы — это функции. То, что они добавляют синтаксический сахар, не означает, что вам не нужно быть осторожным с памятью. Вы должны управлять памятью так же, как и с любой другой функцией-членом/глобальной/другой.

Это особенно важно при перегрузке при реализации класса указателя-оболочки.

Затем происходит конкатенация строк путем перегрузки operator+ или operator+=. Взгляните на шаблон basic_string для получения дополнительной информации.

person dirkgently    schedule 25.03.2009

Если вы сравниваете перегрузку операторов между Java и C++, вы не будете говорить о new и delete — Java не предоставляет достаточно подробностей управления памятью для new и не требует удаления.

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

Таким образом, операторы в C++ работают со значениями или постоянными ссылками на значения.

Было бы очень необычно, если бы операторы, которые оперируют значениями или const ссылаются на значения, возвращали бы что-либо, кроме значения.

Помимо очевидных ошибок, общих для всех функций C++ — возврата ссылки на объект, выделенный в стеке (что противоположно утечке памяти), или возврата ссылки на объект, созданный с помощью new, а не значения (что обычно делается не более более одного раза в карьере до обучения), было бы трудно придумать сценарий, в котором у обычных операторов были бы проблемы с памятью.

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

Аргументы оператора — это объекты, которые передаются либо как значения, либо как ссылки. В C++ нет переносимого механизма для проверки того, был ли объект выделен в куче или стеке. Если объект был передан по значению, он всегда будет в стеке. Таким образом, если бы было требование изменить поведение операторов для двух случаев, это было бы невозможно сделать переносимым в C++. (во многих ОС вы могли бы проверить, находится ли указатель на объект в пространстве, обычно используемом для стека, или в пространстве, обычно используемом для кучи, но это не является ни переносимым, ни полностью надежным.) (также, даже если бы у вас были операторы который принимает два указателя в качестве аргументов, нет причин полагать, что объекты размещаются в куче только потому, что они являются указателями. Эта информация просто не существует в С++)

Единственное дублирование, которое вы получаете, — это такие случаи, как оператор [], где один и тот же оператор используется как в качестве средства доступа, так и в качестве мутатора. Тогда нормально иметь константную и неконстантную версии, поэтому вы можете установить значение, если получатель не является константным. Это хорошо - нельзя изменять (общедоступное состояние) объекты, которые были помечены как константы.

person Pete Kirkham    schedule 25.03.2009