2010-10-20 4 views
2

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

AguiBitmap::AguiBitmap(const AguiBitmap &bmp) 
    { 

     this->nativeBitmapPtr = al_clone_bitmap(bmp.nativeBitmapPtr); 
    } 

    AguiBitmap::AguiBitmap(char *filename) 
    { 

     if(!filename) 
     { 
      nativeBitmapPtr = 0; 
      return; 
     } 

     nativeBitmapPtr = al_load_bitmap(filename); 

     if(nativeBitmapPtr) 
     { 

      width = al_get_bitmap_width(nativeBitmapPtr); 
      height = al_get_bitmap_height(nativeBitmapPtr); 
     } 
     else 
     { 
      width = 0; 
      height = 0; 
     } 
    } 




    ALLEGRO_BITMAP* AguiBitmap::getBitmap() const 
    { 
     return nativeBitmapPtr; 
    } 

Однако Когда я сделать что-то вроде:

AguiBitmap bitmap; 
bitmap = AguiBitmap("somepath"); 

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

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

Благодаря

ответ

12

Этот бит кода обыкновение вызывать конструктор копирования - он вызывает оператор присваивания (или оператор копирования назначения):

// a helper `swap` function 
void AguiBitmap::swap(AguiBitmap& a, AguiBitmap& b) 
{ 
    using std::swap; // enable the following calls to come from `std::swap` 
         // if there's no better match 

    swap(a.nativeBitmapPtr, b.nativeBitmapPtr); 
    swap(a.width, b.width); 
    swap(a.height,b.height); 
} 

AguiBitmap::AguiBitmap& operator=(const AguiBitmap &rhs) 
{ 
    // use copy-swap idiom to perform assignment 
    AguiBitmap tmp(rhs); 

    swap(*this, tmp); 
    return *this; 
} 

Также обратите внимание, что ваш конструктор копирования является неполным, так как height и width члены не копируются:

width = bmp.width; 
height = bmp.height; 
+0

О, хорошо спасибо – jmasterx

+0

Я не думаю, что этот обмен будет работать так, как есть. Во-первых, вы должны поместить 'using std :: swap' в эту' swap() 'свою функцию, чтобы выбрать' std :: swap() '. Во-вторых, в операторе присваивания либо вызовите член класса 'swap (tmp)', либо (лучше) добавьте специализацию/перегрузку для свободной функции 'swap()'. – sbi

+0

@sbi: вы правы, что там должно быть 'использование std :: swap'. И то, что вы описываете, это то, что делает оператор присваивания - «помощник» «AguiBitmap :: swap()» предназначен для статического члена класса «AguiBitmap». Если предпочтение состоит в том, чтобы сделать его нестационарным членом, который принимает только «другой» аргумент или явную специализацию шаблонного 'std :: swap', который, безусловно, можно было бы сделать. –

2

К сожалению, вот задание, а не копию

+1

Что делать, чтобы потом перераспределить память? Поскольку деструктор терпит неудачу, когда временный объект умирает. – jmasterx

2

Вы можете реализовать operator=. Чтобы избежать дублирования кода, используйте его конструктор копирования для его реализации (поскольку они должны делать почти то же самое). Это приведет к тому, что конструктор копирования будет вызван, если косвенно.

This question охватывает, как реализовать это вещество безопасно и эффективно.

7
AguiBitmap("somepath"); 

будет вызывать:

AguiBitmap::AguiBitmap(char *filename) 

и назначение будет вызывать оператор присваивания

ссылаться на ваш конструктор копирования, выполните следующие действия:

AguiBitmap bitmap; 
AguiBitmap anotherBitmap(bitmap) 
3

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

AguiBitmap bitmap = AguiBitmap("somepath"); 

но компилятор может точно также оптимизировать это и выполнить эквивалент этого вместо:

AguiBitmap bitmap("somepath"); 

Однако, согласно Rule of Three, когда у вас есть конструктор копий, вы, скорее всего, тоже потребуете оператора присваивания (и деструктора). Поэтому вы должны его реализовать.
См. this answer для идиоматического способа реализации задания поверх копирования и уничтожения.

+4

Этот код вызывает конструктор 'AguiBitmap (char * filename)', а не конструктор копирования. – sje397

+0

@ sje397: Да, очень глупо. Спасибо, что указали это. – sbi

0

Вам нужно что-то вроде этого:

AguiBitmap &AguiBitmap::operator=(const AguiBitmap &guiBitmap) 
{ 
    if(&guiBitmap == NULL) 
    { 
     //throw Exception 
    } 

    if(&guiBitmap != this) 
    { 
     //do the copying here 
     this->nativeBitmapPtr = al_clone_bitmap(guiBitmap.nativeBitmapPtr); 
     //... 
    } 

    return *this; 
} 
+0

Никто нормальный не написал бы такой ужасный оператор назначения. А второй, если требуется только в некоторых особых случаях. –

+0

@VJo Можете ли вы отправить мне ссылку на пример менее «ужасного оператора назначения»? Второй, если требуется только в «специальном случае», где вы не хотите запускать всю «копию», когда оба объекта одинаковы, или я ошибаюсь? – AudioDroid

+0

http://www.parashift.com/c++-faq-lite/assignment-operators.html объясняет оператор присваивания. Все зависит от того, что вы хотите сделать. 1) ссылка должна указывать на объект (в противном случае у вас есть UB) 2) вы правы о самопроверке –

Смежные вопросы