Как мне инициализировать значение указателя Type*, используя синтаксис, подобный Type()?

Переменные встроенных типов ">может быть инициализировано значением следующим образом:

int var = int();

таким образом я получаю значение по умолчанию int без жесткого кодирования нуля в моем коде.

Однако, если я попытаюсь сделать аналогичные вещи для указателя:

int* ptr = int*();

компилятор (Visual C++ 10) отказывается это компилировать (говорит type int unexpected).

Как мне инициализировать значение указателя аналогичным образом?


person sharptooth    schedule 09.11.2011    source источник
comment
Хороший вопрос. Вы также получаете аналогичный сбой для unsigned int.   -  person Mike Seymour    schedule 09.11.2011
comment
Теперь вопрос в том, почему вы хотите это сделать. Вы можете напрямую инициализировать указатели с 0 (если вы знаете, что это указатель), и если это скрыто в каком-то шаблоне, то T() будет работать нормально... Я не понимаю, как этот вопрос получает 11 голосов :)   -  person David Rodríguez - dribeas    schedule 09.11.2011


Ответы (7)


Как мне инициализировать значение указателя Type*, используя синтаксис, подобный Type()?

Тебе нельзя. Синтаксис T() определен в 5.2.3/1,2 (C++03, немного другая формулировка в C++11 FDIS). В частности, во втором абзаце говорится:

Выражение T(), где T — спецификатор простого типа (7.1.5.2) для полного типа объекта, не являющегося массивом, или типа void (возможно, с указанием cv), создает rvalue указанного типа, который является значением -инициализированный (8.5);

Это означает, что int() создаст rvalue типа int и инициализирует значение. Теперь проблема в том, что int* - это не простой спецификатор типа, а скорее сложный спецификатор типа. Определение спецификатора простого типа в грамматике:

  simple-type-specifier:
    ::opt nested-name-specifieropt type-name
    ::opt nested-name-specifier template template-id
    char
    wchar_t
    bool
    short
    int
    long
    signed
    unsigned
    float
    double
    void

С именем типа, определяемым как:

  type-name:
    class-name
    enum-name
    typedef-name

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

person David Rodríguez - dribeas    schedule 09.11.2011

Используйте typedef, чтобы сделать имя для вашего типа указателя:

typedef int *ip;

ip ptr = ip();

Та же идея должна работать для других типов, которым требуется более одного лексического элемента (слова) для определения имени типа (например, unsigned long, long long, unsigned long long * и т. д.).

person Jerry Coffin    schedule 09.11.2011
comment
Я запутался, указатель просто хранит адрес в памяти переменной - разве он не должен быть просто int* x = int(), заставляя x удерживать 0, что совпадает с NULL? Думаю, я что-то упускаю, так как люди продолжают пропускать мимо меня, ха-ха, но я не понимаю, что. - person John Humphreys; 09.11.2011
comment
@ w00te: у вас будет тот же эффект, потому что 0 определен для преобразования в нулевой указатель. В то же время он специально спрашивает о том, как выполнить инициализацию значения, а вы не делаете этого (инициализация значения имеет конкретное определенное значение в стандарте C++, которое немного отличается от простого общая идея инициализации со значением). - person Jerry Coffin; 09.11.2011
comment
Ах, я подумал, что он просто хотел убедиться, что его указатель указывает на ноль, чтобы его можно было более эффективно проверить в более позднем коде :) Думаю, я неправильно понял. - person John Humphreys; 09.11.2011

Не требует использования typedef (но исключительно для C++11), что может быть полезно при работе с несколькими типами указателей:

template<typename T>
using alias = T;

тогда alias<int*> равно int*, так что вы можете сделать int* p = alias<int*>().

Аналогичное решение доступно для С++ 03 с использованием метафункции идентификации:

template<typename T>
struct identity {
    typedef T type;
};

int* p = identity<int*>::type();
person Luc Danton    schedule 09.11.2011
comment
Для версии C++03 требуется typedef, он просто скрыт внутри шаблона. Версия C++11 не создает typedef, но создает новый тип alias<T>, который становится спецификатором простого типа и, таким образом, подвержен явному преобразованию типов в функциональная нотация - person David Rodríguez - dribeas; 09.11.2011

Вот один из способов:

template <typename T>
T make_default()
{
    return T();
}

int main()
{
    int *p = make_default<int*>();
}
person Stuart Golodetz    schedule 09.11.2011

Просто сделать

int* x = int();

Он по-прежнему присваивает 0 указателю, заставляя его указывать на NULL-адрес, поскольку вы по умолчанию используете значение int по умолчанию, которое в любом случае равно 0.

На самом деле, он отлично работает для всех типов:

double* y = int();

Адрес по-прежнему является 32-битным (или 64-битным в зависимости от платформы) целым числом, поэтому я думаю, что он должен нормально работать для всех типов, если вы делаете = int().

person John Humphreys    schedule 09.11.2011
comment
Вау, похоже на серьезную брешь в системе типов, и это невероятно круто. Но это не сработает для double*. - person sharptooth; 09.11.2011
comment
ага, интересно :) Надо будет проверить. Я думал, что это будет работать для всех типов указателей. - person John Humphreys; 09.11.2011
comment
Да, я имел в виду double* ptr = double(), что, конечно, не сработает. - person sharptooth; 09.11.2011

Причина, по которой это не работает, заключается в том, что указатели не имеют конструкторов.

Синтаксис

int ()

звонки (теоретически)

int::int ()

который инициализирует переменную. (Скорее всего, компилятор просто обнуляет переменную, но это потому, что он «знает» о целых числах).

В С++ 11 вы можете использовать nullptr

int *ptr = nullptr;

В противном случае вам в значительной степени придется использовать NULL:

int *ptr = NULL;

person Marshall Clow    schedule 09.11.2011
comment
Конечно, указатели имеют конструкторы точно так же, как int — в конце концов, все они встроенные. Я могу сказать T(), если T равно typedef int* T, и я также не могу использовать = unsigned int(). Это просто чисто синтаксическая проблема, связанная с тем, что это не работает с составными именами типов. - person sbi; 22.11.2011

Вот как это делается int* ptr = new int;

указатели кучи

person Chris Condy    schedule 09.11.2011