Что было наиболее полезным, когда вы использовали указатель на указатель и / или указатель на указатель в проекте c / c ++? - PullRequest
1 голос
/ 19 января 2010

Указатели на указатели и ссылки на указатели на первый взгляд кажутся слишком сложными, особенно для новичков.Какова лучшая и наиболее полезная причина, по которой вы использовали одну из них в проекте ac / c ++, над которым работали?

Это может помочь людям лучше понять указатели и способы их эффективного использования.

Отредактировано: включены C, а также C ++

Ответы [ 11 ]

4 голосов
/ 19 января 2010

Указатели на указатели очень часто используются в качестве параметров, которые выделяют и возвращают буфер, такой как строка:

void SetValue(char** buf)
{
    string s = "Hello, Ptr Ref";
    *buf = new char[s.length()+1];
    copy(s.begin(), s.end(), *buf);
    (*buf)[s.length()] = 0;
}


int main()
{
    char* buf = 0;
    SetValue(&buf);
    cout << buf;
    delete [] buf;
    return 0;
}

Аналогично, вместо того, чтобы передавать указатель на указатель на буфер, который вы хотите выделить и изменить, вы можете передать ссылку на этот буфер. Это может помочь выяснить семантику вашей функции для вызывающей стороны, чтобы они не делали что-то вроде вызова SetValue(0);

void SetValue(char*& buf)
{
    string s = "Hello, Ptr Ref";
    buf = new char[s.length()+1];
    copy(s.begin(), s.end(), buf);
    buf[s.length()] = 0;
}


int main()
{
    char* buf = 0;
    SetValue(buf);
    cout << buf;
    delete [] buf;
    return 0;
}

Но даже несмотря на то, что семантика SetValue(char*&) может быть немного яснее, чем версия SetValue(char**), все еще есть возможности для улучшения. На ум приходит вопрос, кому принадлежит полученный указатель.

Имейте в виду, что хотя эти примеры являются упрощенными и надуманными, таких реализаций предостаточно. Во многих из тех случаев, когда это делается, у вас нет выбора - например, при вызове функций WINAPI, таких как FormatMessage () и запросе о выделении буфера. Но во многих других случаях, когда вы пишете эту функцию, будут другие способы снять шкуру с кошки. Возможно, лучшие способы. Такие как:

string GimmeValue()
{
  return "Hello, String";
}

Это может быть лучше по ряду причин. (Потенциально) семантически более понятно возвращать значение по значению, чем использовать выходы, такие как указатели на указатели, потому что вопрос о собственности легко решается. Часто лучше избегать использования оператора new в тех случаях, когда переменная, выделенная стеком, будет работать нормально, поскольку вы избегаете потенциальных утечек или дефектов памяти из-за delete многократного использования буфера.

2 голосов
/ 20 января 2010

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

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

Таким образом, вы создаете массив, содержащий указатели на объекты, которые необходимо пройти, а затем сортируете этот массив.

Итератор вэтот массив является указателем на указатель.

Для сортировки с помощью std::sort требуется пара итераторов, что означает, что для него требуется пара указателей на указатели.

И затем его обход с помощьюstd::for_each также требуется пара итераторов.

Это контекст, в котором я последний раз использовал указатели на указатели.(На самом деле у меня был один последний уровень абстракции, поэтому я получил указатели на указатели на указатели, но это, вероятно, более необычно)

2 голосов
/ 19 января 2010

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

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

Указатели науказатели почти неизбежны в C, но в C ++ стандартная библиотека уже имеет контейнерные классы - например, если вам нужен динамический массив строк динамического размера в C, почти единственный выбор - начать с char **, иРаспределяйте фигуры динамически.В C ++ вы обычно хотите вместо этого использовать std::vector<std::string>.Вы по-прежнему сталкиваетесь с ними, когда / если вы решите реализовать свои собственные контейнеры, но это довольно редкое явление (по крайней мере, вам нужно начинать с необработанных указателей и т. Д. Вместо построения поверх существующих контейнеров).

2 голосов
/ 19 января 2010

Указатели к указателям?Динамически распределяемые 2D массивы!

1 голос
/ 20 января 2010

Передача массива значений, представляющих содержимое файла TIFF для геообработки.

0 голосов
/ 20 января 2010

Функция сортировки для шаблонного отсортированного вектора.Это довольно реалистичный пример:

template <typename T>
class Vector {
public:
    typedef bool SortFunc(const T& left, const T& right) ;
    void SetSort(SortFunc* pFunc){}
};


bool intSort(const int& left, const int& right)
{
    return true;
}

bool pintSort( int* const & left, int* const & right)
{
    return true;
}

//in main

Vector<int> intVec;
Vector<int*> pintVec;

intVec.SetSort(&intSort);
pintVec.SetSort(&pintSort);

Учитывая тот факт, что мы можем передать что-либо в качестве векторного параметра, использование ссылок на константы в качестве параметров функции сортировки довольно разумно.Что не является нормальным, так это работает, как натянуть кровавые звездочки, амперсанды и consts для получения константной ссылки на неконстантный целочисленный указатель .

0 голосов
/ 19 января 2010

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

0 голосов
/ 19 января 2010

Однажды я использовал параметр char *** arg для функции, чтобы обновить динамически размещенный массив, похожий на argv, а также для того, чтобы напугать begeebies моих коллег.

0 голосов
/ 19 января 2010

COM - любой метод, который возвращает интерфейс, должен иметь указатель на параметр указателя, чтобы иметь возможность.

0 голосов
/ 19 января 2010

Скажем, вы хотите вернуть выделенный вами буфер или вам может потребоваться перераспределить переданный в него буфер.

Вы можете либо вернуть указатель на буфер, либо передать вызывающему абоненту адресуказателя (таким образом, у вас есть указатель на указатель), и установите этот указатель так, чтобы он указывал на ваш буфер.

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