ссылка на двойной указатель в C ++ - PullRequest
2 голосов
/ 11 апреля 2011

Это может быть глупый вопрос, но я все равно его задам:

Предположим, у вас есть указатель: Object* pointer, указывающий на динамически размещенный объект.

class PointClass
{
 Array<Object*> m_array1;
 Array<Object*> m_array2;

 void Delete1()
 {
     for (int i = 0; i < m_array1.Length; i++)
     {
         delete m_array1[i];
     }
 }

void Delete2()
{
    for (int i = 0; i < m_array2.Length; i++)
    {
        delete m_array2[i];
    }
 }
}

Теперь вы помещаете указатель как в m_array1, так и в m_array2.

Когда вы пытаетесь удалить массивы, в одном из них у вас будет указатель, который указывает на освобожденное пространство, так что вы можетеНе удаляйте его снова!

Я не могу просто назначить указатели NULL после удаления, потому что это не повлияет на указатель в другом массиве.

Как бы вы решили это?

Ответы [ 7 ]

6 голосов
/ 11 апреля 2011

Что ж, самый простой способ - использовать указатель подсчета ссылок, такой как доступен в boost :: smart_ptrs .

В противном случае вам нужно назначить владельцев к указателям - вам нужно решить, какой класс будет отвечать за размещение / удаление этого конкретного указателя.Если по какой-то причине вы решили, что это этот класс, то вы можете удалить дубликаты из массивов, добавив все указатели в set перед их перечислением.

2 голосов
/ 11 апреля 2011

Если вам нужно делить указатели таким образом, что-то вроде указателя с подсчетом ссылок может работать хорошо.

См. Этот сайт, на котором представлены различные методы «умного указателя». Умные указатели

1 голос
/ 11 апреля 2011

Мой первоначальный ответ: не делай этого.

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

0 голосов
/ 11 апреля 2011

Как и другие предлагали использовать умные указатели для решения вашей проблемы. Если вам нужно решить ее, написав свой собственный код, я бы заставил каждую функцию удаления также искать в «другом» массиве, чтобы удалить все указатели в первом массиве, которые можно найти в другом массиве. И это последний вариант, так как это не будет моим первым решением для реализации чего-либо в качестве вашего подхода

void Delete2()
{
    for (int i = 0; i < m_array2.Length; i++)
    {
        for (int j = 0; j < m_array1.Length; j++)
        {
            if (m_array2[i] == m_array1[j])
            {
               delete m_array1[j]
               m_array1[j] = NULL;
            }

            delete m_array2[i];
            m_array2[i] = NULL;
    }
}

Тогда ищи способы его оптимизации

0 голосов
/ 11 апреля 2011

Как бы вы решили это?

Не храня один и тот же указатель в двух разных местах. Это создает дублирование данных и нарушает семантику владения. Кому принадлежит память, на которую указывает pointer? Владение не ясно.

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

0 голосов
/ 11 апреля 2011

Если я понял ваш вопрос, у вас есть одинаковый (действительный) указатель, хранящийся в 2 разных массивах.

Проблема в том, что после удаления его в массиве 1 вы не можете сделать это снова во втором массиве.

Один из способов сделать это - изменить определение массива для хранения адреса памяти самого указателя вместо хранения адреса выделенной памяти:

const int array_size = 3;
int** m_array1[array_size];
int** m_array2[array_size];

, а остальная часть кода может быть реализована как:

void Delete1()
{
     for (int i = 0; i < array_size - 1; i++) // delete all memory but leave the last intact
     {
         if (*(int*)m_array1[i])
         {
             cout << "Delete1: erasing #" << i << " with mem addr " << std::hex << *m_array1[i] << std::dec << endl;
             delete *m_array1[i];
             *m_array1[i] = NULL;
         }
     }
}

void Delete2()
{
    for (int i = 0; i < array_size; i++)
    {
        if (*m_array2[i])
        {
            cout << "Delete2: erasing #" << i << " with mem addr " << std::hex << *m_array2[i] << std::dec << endl;
            delete *m_array2[i];
            *m_array2[i] = NULL;
        }
        else
        {
            cout << "Delete2: !!! memory at #" << i << " was already deleted." << endl;
        }
    }
}

int main()
{
    int* num1 = new int(10);
    int* num2 = new int(20);
    int* num3 = new int(30);

    cout << "main: storing " << std::hex << &num1 << " which points to " << num1 << std::dec << endl;
    cout << "main: storing " << std::hex << &num2 << " which points to " << num2 << std::dec << endl;
    cout << "main: storing " << std::hex << &num3 << " which points to " << num3 << std::dec << endl;

    m_array1[0] = &num1;
    m_array1[1] = &num2;
    m_array1[2] = &num3;

    m_array2[0] = &num1;
    m_array2[1] = &num2;
    m_array2[2] = &num3;

    Delete1();
    Delete2();
}

Выходы:

main: storing 0xbfc3818c which points to 0x87b6008
main: storing 0xbfc38188 which points to 0x87b6018
main: storing 0xbfc38184 which points to 0x87b6028
Delete1: erasing #0 with mem addr 0x87b6008
Delete1: erasing #1 with mem addr 0x87b6018
Delete2: !!! memory at #0 was already deleted.
Delete2: !!! memory at #1 was already deleted.
Delete2: erasing #2 with mem addr 0x87b6028
0 голосов
/ 11 апреля 2011

Лучшее решение - не передавать один и тот же указатель на оба массива. : P Если вам действительно нужно, и вам также нужно отразить это изменение на всех других «одинаковых» указателях, подойдет указатель на указатель.

#include <iostream>
struct Object{};

int main(){
  Object* ptr = new Object;
  Object** ptrptr = &ptr;
  delete *ptrptr;
  *ptrptr = 0;
  // both print 0
  std::cout << *ptrptr << std::endl;
  std::cout << ptr << std::endl;
}

On Ideone .
Другой способ - ссылка на указатель.

int main(){
  Object* ptr = new Object;
  Object*& refptr = ptr;
  delete refptr;
  refptr = 0;
  // both print 0
  std::cout << refptr << std::endl;
  std::cout << ptr << std::endl;
}

Но второй лучший способ - это, вероятно, умный указатель с пересчетом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...