Пустой указатель приведен C ++ и GTK - PullRequest
2 голосов
/ 08 июня 2010

См. Эту функцию обратного вызова GTK:

static gboolean callback(GtkWidget *widget, GdkEventButton *event, gpointer *data)
{
    AnyClass *obj = (AnyClass*) data;
    // using obj works
}

(обратите внимание на gpointer * на данных) .И затем сигнал подключается с помощью:

AnyClass *obj2 = new AnyClass();
gtk_signal_connect(/*GTK params (...)*/, callback, obj2);

Смотрите, что * AnyClass будет приведен к gpointer * (void **).На самом деле, это работает сейчас.Прототипом обратного вызова в документации GTK является «данные gpointer», а не «gpointer * data», как показано в коде, я хочу знать, как это может работать?Это безопасно?

Ответы [ 2 ]

2 голосов
/ 08 июня 2010

Это не совсем безопасно, тем более что при использовании приведения в стиле c вы перешли от статического трансляции с T1 * к void * к reinterpret_cast с T1 * к void **.Тем не менее, это работает, потому что стандарт гарантирует, что вы можете переинтерпретировать трансляцию из T1 * в T2 * (в данном случае T2 = void *) и обратно, чтобы получить тот же T1 *, с которым вы начали .... Требования выравнивания IFF для T1 *T2 * одинаковы.

Другими словами, он будет работать на большинстве реализаций.Приведение к / от void * гарантировано, но я не знаю, есть ли какие-либо требования для void **.

Выполнение reinterpret_cast всегда довольно рискованно.Вы должны правильно настроить T1 с обеих сторон, и компилятор не сможет вам помочь, если вы ошиблись.Например, если вы приведете из класса T5, который является подклассом T1, а затем с другой стороны приведете к T1 * ... вы можете быть полностью облажались.Я полагаю, что static_cast объяснил бы это, но reinterpret_cast - нет.Это может работать нормально, пока кто-то не использует множественное наследование по T5 по любой причине.

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

ПРИМЕЧАНИЕ: мой ответ касается языка C ++.Вы пометили свой вопрос как оба, так что вы обязательно получите ответы на оба вопроса, и они будут очень разными.

1 голос
/ 08 июня 2010

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

Предположим, что ваш новый AnyClass объект выделен в 0x12345678.

AnyClass *obj2 = new AnyClass(); // obj2 = 0x12345678

Затем вы передаете его адрес gtk_signal_connect (примечание: вы должны использовать g_signal_connect):

gtk_signal_connect (/* args */, 0x12345678);

Затем вызывается ваш обратный вызов с указанными вами параметрами аргумента:

callback (address_of_widget, address_of_event_structore, 0x12345678); // because you passed 0x12345678 in gtk_signal_connect

Теперь, поскольку 0x12345678 является действительным адресом, вы можете привести его к действительному указателю AnyClass. data аргумент может быть определен как gpointer************, это не имеет значения, потому что, когда вы преобразуете его в AnyClass*, вы все равно выбрасываете информацию оригинального типа.

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