tozhe_skazo4nik ([info]tozhe_skazo4nik) wrote,
@ 2009-05-13 12:32:00
Previous Entry  Add to memories!  Tell a Friend  Next Entry
 Всё-таки, стандарт С++ 99-го года попытался убрать сложность указателей, введя ссылки. И это здорово. К сожалению, они остановились на пол-пути. К сожалению, ссылка так и осталась недоделанной. Теперь я могу сказать об этом отчётливо, поскольку фреймворк, на котором я работаю, активно использует ссылки (ни одного new/delete в программе без потери производительности).

Что же они упустили, с моей точки зрения, в С++ :

  • Ссылки нельзя переинициализировать. Скажем, если класс обменивается сообщением с объектом, инициализируемым во время, например, десериализации из XML. Так вот, я не могу сделать этот член ссылкой. Потому что инициализируется она обязательно в списке инициализации конструктора. То есть приходится делать указатель, там где без него можно было обойтись. В конечном итоге, я думаю что ссылка должна изначально быть неявным NULL (с выбросом ASSERT в отладочной версии при попытке обращения), и позволять (пере)инициализироваться при желании.
  •  

  • Для ссылок нельзя выполнить виртуальный вызов. Вместо того, чтобы проходить по адресу в таблице виртуальных функций var._vtable[ID_Foo](...), компилятор автоматически вызывает var.Type::Foo(...). А ведь это неправильно: фактически, ссылка это ведь указатель, а значит правильнее было бы сохранять виртуальные вызовы.
  •  

  • Отсутствие поддержки pick behaviour и moveable типов. Язык не приветствует ни в каком виде разрушающие операторы= и разрушающие "копирующие конструкторы". А зря. Если расположить в правильных местах, это увеличит производительность в разы. Moveable - это конечно тот ещё хак, но и он экономит (правда, конкретно его не замерял).
  •  

  • Нет возможности на этапе компиляции взять тип аргумента. Это зачастую может быть очень неудобно. В той библиотеке "альтернативной многопоточности", которую я пишу, это бы очень помогло. В этом случае основной вызов вида visualizer.Request(&Visualizer::Update, upData); можно бы было упростить.



(18 comments) - (Post a new comment)


[info]zabivator
2009-05-13 12:52 pm UTC (link)
# Для ссылок нельзя выполнить виртуальный вызов. Вместо того, чтобы проходить по адресу в таблице виртуальных функций, компилятор автоматически вызывает type.Type::Foo(...). А ведь это неправильно: фактически, ссылка это ведь указатель, а значит правильнее было бы сохранять виртуальные вызовы.
Можно. Точно также, как и "адрес виртуальной функции" - вместо собственного адреса - offset в таблице виртуальных функций, а вызов разворачивается в (*vtbl[ index ])( this, ... )

(Reply to this) (Thread)


[info]tozhe_skazo4nik
2009-05-13 01:14 pm UTC (link)
Так я говорю о поддержке на уровне языка, а не о более или менее непереносимых хаках. Речь идёт о том, что для ссылки компилятор разворачивает вызов в простую функцию, а не виртуальную. Вопрос о том, можно ли такое сделать в принципе, не обсуждается - понятно что сделать можно.

(Reply to this) (Parent)(Thread)


[info]zabivator
2009-05-13 01:22 pm UTC (link)
Это не хаки. Это поддерживается на уровне языка.
Попробуй сам
struct IExample
{
virtual void some() = 0;
virtual void other() = 0;
void(IExample::*)() foo( bool a_param )
{
if( param )
return &some;
else
return &other;
}
void make( (void(IExample::*a_methid)() )
{
(this->*a_method)();
}
};

(Reply to this) (Parent)(Thread)


[info]tozhe_skazo4nik
2009-05-13 01:24 pm UTC (link)
Идея ясна. Но речь всё равно не о том.
Простой вызов вида
iexample.Some();
должен разворачиваться в виртуальный вызов

(Reply to this) (Parent)(Thread)


[info]zabivator
2009-05-13 01:26 pm UTC (link)
А разве оно не также?
IExample& e( *some );
(e.*a_method)()

(Reply to this) (Parent)(Thread)


[info]tozhe_skazo4nik
2009-05-13 01:37 pm UTC (link)
Первый вариант читается на порядок лучше. Вообще я считаю что всякие конструкции вида
const IExample * const * &ie
отлично демонстрируют скорее невнятность синтаксиса, переданного по наследству от С, чем какие-то плюсы С++.

(Reply to this) (Parent)


[info]zabivator
2009-05-13 12:53 pm UTC (link)
Ссылки нельзя переинициализировать. Скажем, если класс обменивается сообщением с объектом, инициализируемым во время, например, десериализации из XML. Так вот, я не могу сделать этот член ссылкой. Потому что инициализируется она обязательно в списке инициализации конструктора. То есть приходится делать указатель, там где без него можно было обойтись. В конечном итоге, я думаю что ссылка должна изначально быть неявным NULL (с выбросом ASSERT в отладочной версии при попытке обращения), и позволять (пере)инициализироваться при желании.
Необходимость данного весьма спорна, и может провоцировать ошибки.

(Reply to this) (Thread)


[info]tozhe_skazo4nik
2009-05-13 01:17 pm UTC (link)
Она была для меня спорна в самом начале. Сейчас я пришёл к выводу что она обязательна. То что может провоцировать ошибки - безусловно, но на мой взгляд она решает проблем больше чем создаёт. Просто данная возможность получится, выражаясь словами самого Страуступа, "too expert-friendly".

(Reply to this) (Parent)(Thread)


[info]zabivator
2009-05-13 01:22 pm UTC (link)
=)))

(Reply to this) (Parent)


[info]zabivator
2009-05-13 12:54 pm UTC (link)
# Отсутствие поддержки pick behaviour и moveable типов. Язык не приветствует ни в каком виде разрушающие операторы= и разрушающие "копирующие конструкторы". А зря. Если расположить в правильных местах, это увеличит производительность в разы. Moveable - это конечно тот ещё хак, но и он экономит (правда, конкретно его не замерял).
Ссылки в ту же степь. Я лично декларировал бы возможность это сделать, пусть не очень удобно.

(Reply to this)


[info]zabivator
2009-05-13 12:55 pm UTC (link)
* Нет возможности на этапе компиляции взять тип аргумента. Это зачастую может быть очень неудобно. В той библиотеке "альтернативной многопоточности", которую я пишу, это бы очень помогло. В этом случае основной вызов вида visualizer.Request(&Visualizer::Update, upData); можно бы было упростить.
Жаль, что нету compile-time typeof =( Проблем никаких, а метапрограммирование упростит на порядок.

(Reply to this) (Thread)


[info]tozhe_skazo4nik
2009-05-13 01:20 pm UTC (link)
Согласен. Почему-то С++ не учится у D (а есть чему, на мой взгляд). Я бы сделал нечто подобное, но полностью в статике и без оверхэда (без виртуальных машин, динамического связывания и мусоросборщика) - абсолютно ненужных вещей при верном подходе.

(Reply to this) (Parent)(Thread)


[info]zabivator
2009-05-13 01:23 pm UTC (link)
Согласен полностью
Ещё не хватает compile-time рефлексии... Серализация - реальный ад.

(Reply to this) (Parent)(Thread)


[info]tozhe_skazo4nik
2009-05-13 01:30 pm UTC (link)
А что такое "compile-time рефлексия"?

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

//бинарная
struct Foo {
int q;
String text;
Vector data;

void Serialize(Stream& s)
{
s % q % text % data;
}
}

//XML
struct Data {
Size sz;
int lang;
String text;
Vector vector;
VectorMap
[Error: Irreparable invalid markup ('<string,>') in entry. Owner must fix manually. Raw contents below.]

А что такое "compile-time рефлексия"?

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

//бинарная
struct Foo {
int q;
String text;
Vector<int> data;

void Serialize(Stream& s)
{
s % q % text % data;
}
}

//XML
struct Data {
Size sz;
int lang;
String text;
Vector<Size> vector;
VectorMap<String, int> score;
VectorMap<String, String> map;
ArrayMap<int, Size> sizemap;
double number;
bool option;

void Xmlize(XmlIO xml)
{
xml
("Dimension", sz)
("text", text)
("vector", vector)
("Scores", score)
("map", map)
("sizemap", sizemap)
("number", number)
("option", option)
;
XmlizeLang(xml, "Language", lang);
}
};

(Reply to this) (Parent)(Thread)


[info]zabivator
2009-05-13 01:36 pm UTC (link)
Возможность обойти все поля структуры - получить типы мемберов, смещения.

(Reply to this) (Parent)(Thread)


[info]tozhe_skazo4nik
2009-05-13 01:38 pm UTC (link)
+1
Было бы очень полезно. И, вроде, не должно вызвать никаких проблем при реализации.

(Reply to this) (Parent)(Thread)


[info]zabivator
2009-05-13 01:41 pm UTC (link)
Вот именно. Никакого оверхеда - зато один раз написанный код по сериализации.

(Reply to this) (Parent)(Thread)


[info]tozhe_skazo4nik
2009-05-13 01:43 pm UTC (link)
С другой стороны, я бы не сказал что это

void Serialize(Stream& s)
{
s % q % text % data;
}

глобально хуже.

(Reply to this) (Parent)


(18 comments) - (Post a new comment)

Create an Account
Forgot your login or password?
Login w/ OpenID
English • Español • Deutsch • Русский…