Конструктор копирования сегментов

Мой код выглядит следующим образом:

void Scene::copy(Scene const & source)    
{
maxnum=source.maxnum;
imagelist = new Image*[maxnum];

for(int i=0; i<maxnum; i++)
{
   if(source.imagelist[i] != NULL)
   {
    imagelist[i] = new Image;
    imagelist[i]->xcoord = source.imagelist[i]->xcoord;
    imagelist[i]->ycoord = source.imagelist[i]->ycoord;
    (*imagelist[i])=(*source.imagelist[i]);
   }

   else
   {
   imagelist[i] = NULL;
   }
}
}

Немного предыстории: класс Scene имеет закрытый int с именем maxnum и динамически выделяемый массив указателей на изображения при построении. Эти указатели указывают на изображения. Конструктор копирования пытается сделать глубокую копию всех изображений в массиве. Каким-то образом я получаю Segfault, но я не понимаю, как я буду получать доступ к массиву за пределами.

Кто-нибудь видит что-то не так?

Я новичок в С++, так что это, вероятно, что-то очевидное.

Спасибо,


person Arjun Nayini    schedule 09.02.2010    source источник


Ответы (2)


Я бы предложил, чтобы maxnum (и, возможно, imagelist) стал закрытым элементом данных и реализовал методы const getMaxnum() и setMaxnum(). Но я сомневаюсь, что это является причиной какой-либо неисправности, как вы это описали.

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

Кроме того, вы можете создать отдельный объект класса Scene и передать данные типа изображения в виде указателя массива. И я не думаю, что вы можете объявить Image *imagelist[value];.

void Scene::copy(Image *sourceimagelist, int sourcemaxnum) {  
maxnum=sourcemaxnum;
imagelist=new Image[maxnum];
//...
    imagelist[i].xcoord = sourceimagelist[i].xcoord;
    imagelist[i].ycoord = sourceimagelist[i].ycoord;
//...
}
//...
Scene a,b;  
//...
b.Copy(a.imagelist,a.maxnum);
person mike_b    schedule 09.02.2010

Если для исходного изображения maxnum установлено выше, чем фактическое количество элементов в его списке изображений, то цикл будет выполняться после конца массива source.imagelist. Возможно, maxnum инициализируется значением один, в то время как массив начинается пустым (или maxnum может вообще не инициализироваться), или, может быть, если у вас есть функция Scene::remove_image(), она могла удалить запись списка изображений без уменьшения макс. Я бы предложил использовать std::vector, а не необработанный массив. Вектор будет отслеживать свой собственный размер, поэтому ваш цикл for будет выглядеть так:

for(int i=0; i<source.imagelist.size(); i++)

и он будет иметь доступ только к тому количеству элементов, которое содержится в исходном векторе. Другое возможное объяснение сбоя заключается в том, что один из ваших указателей в source.imagelist принадлежит изображению, которое было удалено, но указатель никогда не был установлен в NULL и теперь является оборванным указателем.

delete source.imagelist[4];
...
...  //  If source.imagelist[4] wasn't set to NULL or removed from the array,
...  //  then we'll have trouble later.
...
for(int i=0; i<maxnum; i++)
{
    if (source.imagelist[i] != NULL)  //  This evaluates to true even when i == 4
    {
        //  When i == 4, we're reading the xcoord member from an Image
        //  object that no longer exists.
        imagelist[i]->xcoord = source.imagelist[i]->xcoord;

Эта последняя строка будет обращаться к памяти, которой не должна. Возможно, объект все еще существует в памяти, потому что он еще не был перезаписан, или, может быть, он был перезаписан, и вы получите недопустимое значение xcoord. Однако, если вам повезет, ваша программа просто рухнет. Если вы имеете дело непосредственно с new и delete, убедитесь, что вы установили указатель на NULL после его удаления, чтобы у вас не было висящего указателя. Это не предотвращает эту проблему, если вы где-то держите копию указателя, и в этом случае вторая копия не будет установлена ​​​​на NULL, когда вы удаляете-и-NULL первую копию. Если позже вы попытаетесь получить доступ ко второй копии указателя, у вас не будет возможности узнать, что он больше не указывает на действительный объект.

Гораздо безопаснее использовать класс интеллектуальных указателей и позволить ему управлять памятью за вас. В стандартной библиотеке C++ есть интеллектуальный указатель с именем std::auto_ptr, но он имеет странную семантику и не может использоваться в контейнерах C++, таких как std::vector. Однако, если у вас установлены библиотеки Boost, я бы предложил заменить необработанные указатели на boost: :shared_ptr.

person Josh Townzen    schedule 09.02.2010