2012-04-04 3 views
2

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

#include <iostream> 
using namespace std; 

class temp 
{  
    public: 

    temp(int i) 
    { 
     intPtr = new int(i); 
    } 

    ~temp() 
    { 
     delete intPtr; 
    } 

    private: 
    int* intPtr; 
}; 

void f (temp fInput) 
{ 
    cout << "f called" << endl; 
} 

int main() 
{ 
    temp x = 2; 
    f(x); 
    return 0; 
} 
+1

Можете ли вы определить "крушение"? – josephthomas

+0

@ Ed S: Я согласен, однако, иногда то, что мы определяем как крушение, может отличаться от того, что, по его мнению, является крахом. – josephthomas

+0

@josephthomas: Да, я так понял, поэтому я удалил свой комментарий вскоре после его публикации :) Мы можем договориться о правильном использовании этого термина ... независимо от того, будут ли его начинающие использовать или нет, это еще одна проблема –

ответ

5

Указатель копируется, когда х передается (неявный конструктор копирования) и деструктор вызывается дважды (до возврата из функции и перед основным возвращается), таким образом, память удаляется дважды.

Используйте std::shared_ptr<int> здесь вместо того, чтобы вместо сырой ИНТ указатель (предполагается, что вы хотите, поведение будет таким же, то есть ссылки на один и тот же int с обеих temp с, в противном случае реализовать конструктор копирования, перемещения конструктор и оператор присваивания самостоятельно).

#include <memory> 

class temp {  
public: 
    temp(int i) : intPtr(std::make_shared<int>(i)) { 

    } 

private: 
    std::shared_ptr<int> intPtr; // reference counting ftw 
}; 
+0

Или просто правильно реализовать класс для начала (т. Е. Правильную семантику копирования и т. Д.) –

+0

Это также возможно, в зависимости от поведения, которое вы хотите. –

+0

.... правильное поведение всегда желательно. –

5

Крушение происходит из-за того, что вы проходите мимо x.

После выполнения функции f будет вызываться деформирование x и удалит intPtr.

Однако, это удалит память, которая по-прежнему находится в области main. Поэтому, после вызова return 0, он попытается удалить память, которая уже существует, поскольку вы дважды вызываете удаление по тому же указателю.

Чтобы исправить эту ошибку, измените

void f (temp fInput) 

в

void f (const temp& fInput) 

В качестве альтернативы, вы можете посмотреть в использовании std::shared_ptr.

+0

Добавление конструктора копирования и оператора присваивания также будет хорошей идеей. Вы также можете использовать std :: shared_ptr вместо необработанного указателя, поскольку он позаботится о семантике копирования. –

+0

Согласен, я хотел, чтобы плакат знал решение, которое могло бы помочь ему в минимальных усилиях. Существует множество способов устранения этой аварии. – josephthomas

5

Вы нарушаете The Rule of Three

Вы поддерживаете элемент указателя и вы передаете копию объекта в функции f. Итак, конечным результатом является то, что вы дважды вызываете delete на том же указателе.

1

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

f(x); 

Эта линия работает путем создания копии x и передавая ее f. На данный момент есть 2 temp экземпляров, в которых есть один член intPtr. Оба экземпляра удаляют этот указатель, и это, скорее всего, приводит к вашему сбою.

Чтобы обойти эту проблему вы можете предпринять ряд шагов

  1. Используйте тип указателя, предназначенную для совместного использования, как shared_ptr<T>
  2. Создание uncallable конструктор копирования, который заставляет экземпляр должен быть принят исх

пример # 2

class temp { 
    temp(const temp& other); 
    temp& operator=(const temp& other); 
public: 
    // Same 
}; 

Теперь строка f(x) просто не будет компилироваться, потому что она не может получить доступ к нужному конструктору копирования. Это заставляет его переопределить f, чтобы предотвратить копирование.

void f(const temp& fInput) { 
    ... 
} 
Смежные вопросы