Здравствуйте, gear nuke, Вы писали:
GN>Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>>>>От basic_string необходим move_type и один конструктор.
GN>То есть больше сломать в стандартном интерфейсе?
Именно сломать (чтобы существующий код перестал компилироваться) — врядли (удалять вроде ничего не надо)
ЮЖ>>operator+ пусть сама реализация оптимизирует(expression templates).
GN>Пока интереснее простые решения. В сабжевом варианте и так страдает диагностика для (un)signed char *
У меня сегодня день тяжелый, я все не могу понять зачем нужен вариант с CT в первом посте И о какой дигностике идет речь...
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>У меня сегодня день тяжелый, я все не могу понять зачем нужен вариант с CT в первом посте
Видимо, иначе конструктор с const charT (&s)[Size] никогда не будет вызван, но могу ошибаться.
Здравствуйте, gear nuke, Вы писали:
GN>Что думаете по поводу замены стандартного конструктора следующей парой?
Подумал такое:
Можно не рассчитывать на то что будет обязательно литерал (как я сначала подумал). Вместо этого не находить длину строки, а сразу копировать в буфер, но при копировании уже определять реальную длину и использовать её как длину строки. Делать это может иметь смысл:
1. Когда в basic_string применена оптимизация, что небольшой статический буфер является полем класса и если в него строка помещается, динамический буфер не выделяется — сразу копировать для таких Size, которые помещаются в буфер. (Такая оптимизация со статическим буфером 16 байт применена в стандартном basic_string MSVC).
2. Когда известно, что аллокатор не очень эффективен, например, выделяет всегда размер, кратный 16 байт и ещё 16 байт оверхеда на каждую аллокацию — для малых Size может иметь смысл выделять возможно больше чем надо, зато не тратить время на определение длины. (такой аллокатор реализуется стандартными функциями выделения MSVC).
Оба случая касаются малых строк, и они, скорее всего, будут литералами. MAX_PATH это 260. Другие подобные константы вряд ли будут менее 20 символов. 12 букв — это "hello world!" а не буфер
Разумеется, надо внимательно оценить всю выгоду, подумать о всех возможных последствиях для legacy кода. "Permature optimization..." и далее по тексту.
Здравствуйте, Alexander G, Вы писали:
AG>Подумал такое: AG>Можно не рассчитывать на то что будет обязательно литерал (как я сначала подумал). Вместо этого не находить длину строки, а сразу копировать в буфер, но при копировании уже определять реальную длину и использовать её как длину строки.
Дополню свой вопрос: В выкидывании traits_type::length специализация traits_type<char> менее интересена, чем пользовательские. Хотя и MSVC грешит:
И потери от некоторых частей boost или других вышестоящих библиотек могут быть более существенны.
AG>1. Когда в basic_string применена оптимизация, что небольшой статический буфер является полем класса и если в него строка помещается, динамический буфер не выделяется — сразу копировать для таких Size, которые помещаются в буфер. (Такая оптимизация со статическим буфером 16 байт применена в стандартном basic_string MSVC).
Делать буфер членом класса может быть накладно, если стек 12Кб. Как раз в предложенном варианте несложно обеспечить поскондиции begin() end() ии без копирования.
AG>Разумеется, надо внимательно оценить всю выгоду, подумать о всех возможных последствиях для legacy кода. "Permature optimization..." и далее по тексту.
Оптимизация аллокатора это отдельная тема Я о попытке следовать принципу "не платить за неиспользуемое". Ведь, фактически, "ничего" и не делается. А если цена — те забавные С функции, то это копейки. И экономятся теже копейки, но это место не на диске, а в кеше команд. Хотя, с другой стороны, нагенерится темплейтов ..
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Здравствуйте, gear nuke, Вы писали:
GN>Что думаете по поводу замены стандартного конструктора следующей парой?
Единственный bullet-proof вариант детектирования строковых литералов, который я вижу:
#include <iostream>
#pragma const_seg(push, old_seg)
#pragma const_seg(".aaaaa")
extern int const data_seg_begin = 1;
#pragma const_seg(".zzzzz")
extern int const data_seg_end = 1;
#pragma const_seg(pop, old_seg)
#pragma comment (linker, "/merge:.aaaaa=.rdata")
#pragma comment (linker, "/merge:.zzzzz=.rdata")
void test(void const* p)
{
void const* begin = &data_seg_begin;
void const* end = &data_seg_end;
bool r = (p > begin && p < end);
std::cout << r << std::endl;
}
int main()
{
char const* sz = "asdasasd";
test(sz);
int i = 0;
test(&i);
test(new int);
}
Если в std::string детектировали, что передаётся литерал, то можно не выделять память, не копировать, в деструкторе не освобождать память, безопасно использовать в многопоточном окружении без защиты. Однако при первой попытке модификации надо делать копию. Длину строки, в принципе, можно сразу тоже не считать. Если будут вызывать, например, только c_str(), то она нам и не понадобится. Но если будут звать length(), то длину всё равно придётся лениво считать, т.к. с текущим интерфейсом std::string и с возможностью класть в строковые литералы '\0', определять её на этапе компиляции не получится.
Здравствуйте, gear nuke, Вы писали:
GN>>кому насколько жалко такой код. GN>Имеется ввиду, что приведёные примеры отпадают т.к такой код выкидывается. Но #if делается не 0, чтобы ничего не терять
Я что-то ничего не понял из этих двух сообщений. Какой код, что жалко, причём здесь #if...
Здравствуйте, Кодт, Вы писали:
К>Какой код, что жалко,
Если сломается только код, подобный приведённым в топе примерам, это допустимо. При выкидывании traits_type<char>::length() более опасными кажутся проблемы с пользовательскими traits_type.
К>причём здесь #if...
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Здравствуйте, remark, Вы писали:
R>Если в std::string детектировали, что передаётся литерал, то можно не выделять память, не копировать, в деструкторе не освобождать память, безопасно использовать в многопоточном окружении без защиты. Однако при первой попытке модификации надо делать копию.
Опасная практика. Я уже пробовал подобную фигню делать. А потом напоролся на конструирование экземпляра на литерале из ДЛЛ-ки, которая впоследствии выгружалась. В итоге отказался от этого.
R>
Здравствуйте, McQwerty, Вы писали:
R>>Если в std::string детектировали, что передаётся литерал, то можно не выделять память, не копировать, в деструкторе не освобождать память, безопасно использовать в многопоточном окружении без защиты. Однако при первой попытке модификации надо делать копию.
MQ>Опасная практика.
Бесспорно.
MQ>Я уже пробовал подобную фигню делать. А потом напоролся на конструирование экземпляра на литерале из ДЛЛ-ки, которая впоследствии выгружалась. В итоге отказался от этого.
Кстати, как я предложил, должны детектироваться литералы только из основной программы, но не из динамических библиотек.
[]
R>Если в std::string детектировали, что передаётся литерал, то можно не выделять память, не копировать, в деструкторе не освобождать память
Кстати, это можно делать и без изменения стандартного интерфейса — всё равно проверка будет в рантайме (а если уж изменять, как было предложено, то и на проверку попадания в сегмент можно попробовать забить). Но для других функцияй-членов предложение ничего не даст.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Здравствуйте, gear nuke, Вы писали:
R>>Если в std::string детектировали, что передаётся литерал, то можно не выделять память, не копировать, в деструкторе не освобождать память
GN>Кстати, это можно делать и без изменения стандартного интерфейса — всё равно проверка будет в рантайме (а если уж изменять, как было предложено, то и на проверку попадания в сегмент можно попробовать забить). Но для других функцияй-членов предложение ничего не даст.
Я и имел в виду случай, когда мы не изменяем интерфейс. Я так понимаю, что изначально речь была именно о такой ситуации. А так-то в целом, я за вариант, что пользователь явно говорит "держи строку, но не управляй временем её жизни", или "это строковый литерал без нулей в середине, можешь посчитать длину во время компиляции" и т.д.
Здравствуйте, remark, Вы писали:
R>Я и имел в виду случай, когда мы не изменяем интерфейс. Я так понимаю, что изначально речь была именно о такой ситуации. А так-то в целом, я за вариант, что пользователь явно говорит "держи строку, но не управляй временем её жизни", или "это строковый литерал без нулей в середине, можешь посчитать длину во время компиляции" и т.д.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, remark, Вы писали:
R>>Я и имел в виду случай, когда мы не изменяем интерфейс. Я так понимаю, что изначально речь была именно о такой ситуации. А так-то в целом, я за вариант, что пользователь явно говорит "держи строку, но не управляй временем её жизни", или "это строковый литерал без нулей в середине, можешь посчитать длину во время компиляции" и т.д.
E>А у тебя есть идеи, как это будет выглядеть в коде? Или же тебе нравится вариант Кодт-а: http://www.rsdn.ru/forum/message/3085983.1.aspx
У тегов очень простой неостаток — обратная совместимость ломается. Что бы их использовать, потребуется изменения в клиентском коде. И потом этот клиентский код нельзя будет использовать со стандартной библиотекой, например, что бы протестить на предмет улучшения скорости
В моём варианте может сломаеться старый код (причём, судя по приведённым здесь примерам, этот код и так слудует выкинуть). Новый код пишется и работает нормально с любой версией.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Здравствуйте, gear nuke, Вы писали:
GN>Здравствуйте, remark,
GN>У тегов очень простой неостаток — обратная совместимость ломается. Что бы их использовать, потребуется изменения в клиентском коде. И потом этот клиентский код нельзя будет использовать со стандартной библиотекой, например, что бы протестить на предмет улучшения скорости
GN>В моём варианте может сломаеться старый код (причём, судя по приведённым здесь примерам, этот код и так слудует выкинуть). Новый код пишется и работает нормально с любой версией.
С тегами ничего ломаться не будет при правильно выбранном поведении по-умолчанию, т.е. когда тэг не задан.
Далее в самых критичных местах постепенно дабавляешь нужные тэги.
Ну а новый код-то по-любому и с тэгами будет работать нормально.
Здравствуйте, remark, Вы писали:
R>Ну а новый код-то по-любому и с тэгами будет работать нормально.
Я исхожу из того, что новые конструкторы с тегами не будут приняты Коммитетом. Так что новый код не будет работать со стандартными реализациями.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Здравствуйте, gear nuke, Вы писали:
R>>Ну а новый код-то по-любому и с тэгами будет работать нормально.
GN>Я исхожу из того, что новые конструкторы с тегами не будут приняты Коммитетом. Так что новый код не будет работать со стандартными реализациями.
template<typename char_t, size_t size>
struct tag_string_literal_t
{
tag_string_literal(char const* sz)
: sz_(sz)
{}
char const* sz_;
operator char const* ()
{
return sz;
}
};
template<typename char_t, size_t size>
tag_string_literal_t<char_t, size> tag_string_literal(char_t const (&sz) [size])
{
return tag_string_literal_t<char_t, size>(sz);
};
std::string s (tag_string_literal("foo")); // работает оператор приведения к char const*
my_super_string ss (tag_string_literal("foo")); // понимает, что ему передают строковый литерал
Здравствуйте, gear nuke, Вы писали:
GN>В моём варианте может сломаеться старый код (причём, судя по приведённым здесь примерам, этот код и так слудует выкинуть). Новый код пишется и работает нормально с любой версией.
typedef struct _PHYSICAL_MONITOR {
HANDLE hPhysicalMonitor;
WCHAR szPhysicalMonitorDescription[PHYSICAL_MONITOR_DESCRIPTION_SIZE];
} PHYSICAL_MONITOR, *LPPHYSICAL_MONITOR;
...
A physical monitor description is always an array of 128 characters.
Обратите внимание, что:
1. буфер используется для передачи *из* WinAPI, т.е. конструирование wstring из него реально.
2. структура используется в функциях, появившихся только в Vista, т.е. написан этот код не так давно.
#include <string>
R>std::string s (tag_string_literal("foo")); // не работает, undefined simbol: tag_string_literal
R>my_super_string ss (tag_string_literal("foo")); //
R>
То есть, предлагается перенести тэги в клиентский код? И эти теги будут завязаны на реализацию нижележащей стандартной библиотеки?
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Здравствуйте, Alexander G, Вы писали:
AG>На самом деле такой legacy код до сих пор пишут.
Может быть потому, что нет выбора? Точнее, выбор такой: есть C API и С++, можно писать на C, можно один раз ниписать обёртку на C++ и везде использовать её Теперь представим, что на замену старому, есть только C++ API, у пользователей опять "нет выбора" — они будут использовать обёртки без указанных здесь проблем.
Старый код при необходимости рефакторится, либо определяем макрос:
#ifdef C_CONFORMING_STD_STRING
basic_string(const charT* s, size_type n, const Allocator& a = Allocator())
#else
AG>2. структура используется в функциях, появившихся только в Vista, т.е. написан этот код не так давно.
А другого выбора у MS и нет. У них всё АПИ на С (не из-за неприятия С++, а для совместимости с другими языками).
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth