2015-08-27 5 views
0

Мое настоящее понимание заключается в том, что и Операции перемещения и копирования C++ 11 Операторы должны вызывать удаление, чтобы предотвратить утечку памяти, , но что C++ 11 Перемещение и копирование Конструкторы должны не.C++ 11 Назначение переадресации и назначение копирования (операторы) - Использование удаления

Если мое понимание верное, конструкторам не нужно звонить delete, однако я не знаю, почему. Рассмотрим следующий пример:

class my_class 
{ 
    my_class(int num_data) : my_data{new double[num_data]}, my_data_length{num_data} 
    { 
    } 

    // This class manages a resource 
    double *my_data; 
    int my_data_length; 
} 

// Big 4 go here - see wikipedia example below. 

my_class a(10); 
my_class b(10); 
my_class c(10); 

a = b; // Need to delete old storage contained in a before reallocating 
a(c); // For some reason we don't need to delete the old storage here? I find this puzzling 

Глядя на пример кода из этой wikipedia статьи, мне ясно, что:

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

  • Я смущен относительно того, что утечка Копирования строится.

  • Оператор присваивания движения предположительно не течет, потому что он просто меняет указатели.

  • Я снова смущен Оператором присваивания копий. Я не уверен, почему требуется использование временного объекта? Я предполагаю, что ресурсы, принадлежащие tmp, и other уничтожаются, когда они выходят за пределы области действия в конце этой функции? (За исключением того tmp имеет свои ресурсы местами с указателем в this классе?)

Код от этого приводится ниже для удобства:

#include <cstring> 
#include <iostream> 

class Foo 
{ 
public: 
    /** Default constructor */ 
    Foo() : 
     data (new char[14]) 
    { 
     std::strcpy(data, "Hello, World!"); 
    } 

    /** Copy constructor */ 
    Foo (const Foo& other) : 
     data (new char[std::strlen (other.data) + 1]) 
    { 
     std::strcpy(data, other.data); 
    } 

    /** Move constructor */ 
    Foo (Foo&& other) noexcept : /* noexcept needed to enable optimizations in containers */ 
     data(other.data) 
    { 
     other.data = nullptr; 
    } 

    /** Destructor */ 
    ~Foo() noexcept /* explicitly specified destructors should be annotated noexcept as best-practice */ 
    { 
     delete[] data; 
    } 

    /** Copy assignment operator */ 
    Foo& operator= (const Foo& other) 
    { 
     Foo tmp(other); // re-use copy-constructor 
     *this = std::move(tmp); // re-use move-assignment 
     return *this; 
    } 

    /** Move assignment operator */ 
    Foo& operator= (Foo&& other) noexcept 
    { 
     // simplified move-constructor that also protects against move-to-self. 
     std::swap(data, other.data); // repeat for all elements 
     return *this; 
    } 

private: 
    friend std::ostream& operator<< (std::ostream& os, const Foo& foo) 
    { 
     os << foo.data; 
     return os; 
    } 

    char* data; 
}; 

int main() 
{ 
    const Foo foo; 
    std::cout << foo << std::endl; 

    return 0; 
} 

Я предполагаю, что это намекает на то, почему это важно установить (неинициализированные/нераспределенные) висячие указатели на nullptr, так как это предотвратит ошибки памяти в деструкторе при ее удалении?

Причина, по которой я думаю, что это связано с тем, что ресурсы передаются с помощью конструктора перемещения, но объект с истекающим сроком действия получает оборванный указатель, который никогда не был выделен, - мы не хотим, чтобы деструктор затем вызывался и delete указатель - если мы не гарантируем, что он указывает на nullptr (no-op).

Может кто-нибудь уточнить некоторые из пунктов, которые я поднял?

ответ

0

Конструктор перемещения и оператор присваивания устанавливают указатель данных на nullptr при перемещении права собственности на указатель. Если они этого не сделали, а delete был вызван в оригинале и в новом, у вас будет двойное удаление. Или, если старый был удален, новый будет иметь недопустимый указатель. Между тем, конструктор копирования и оператор присваивания создают полностью отдельную копию данных.

delete на nullptr безопасен и не делает ничего, что вы отметили.

Конструкция Move Constructor не течет из-за передачи ресурсов. Любые выделенные данные, на которые указывает класс, который не истекает, переносятся в истекающий класс и удаляются деструктором истекающего класса.

Да, Move Constructor не течет, потому что ресурсы переданы. Что еще более важно, он никогда не выделяет собственные ресурсы.

Я смущен относительно того, что утечка Копирования строится.

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

Оператор присваивания движения, по-видимому, не течет, поскольку он просто меняет указатели.

Исправить.

Я снова смущен Оператором присваивания копий. Я не уверен, почему требуется использование временного объекта? Я предполагаю, что ресурсы, принадлежащие tmp и другие, уничтожаются, когда они выходят за пределы области действия в конце этой функции? (За исключением, что TMP имеет свои ресурсы местами с указателем в этом классе?)

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

Я предполагаю, что это намекает на то, почему это важно установить (неинициализированные/нераспределенные) висячие указатели на nullptr, так как это позволит предотвратить ошибки памяти в деструкторе при удалении его?

Исправить.