#c #templates #rvalue-reference
#c #шаблоны #rvalue-ссылка
Вопрос:
С появлением ссылок на значения rvalue поверх оптимизации возвращаемого значения, какой был бы наиболее эффективный способ реализации такой базовой функции? Как я могу улучшить эту реализацию или мне следует оставить ее в покое?
template <typename T>
string
to_string(const Tamp; t)
{
stringstream ss;
ss << t;
return ss.str();
}
Очевидно, я хочу избежать копирования или выделения памяти, если смогу.
TIA.
Редактировать: Спасибо Д. Родригесу за этот подробный ответ. Теперь у меня есть вторая часть моего вопроса. Есть ли способ улучшить это?
#define to_cstr( T ) (to_string( T ).c_str())
Конечно, я хотел бы избежать макросов, если смогу, но если я скопирую и вставлю приведенный выше код шаблона, чтобы вернуть ss.str().c_str() и const char* , временное значение не живет достаточно долго; хотя код, кажется, выполняется, valgrind жалуется (красный свет).
Я не смог придумать более чистого решения, чем приведенный выше МАКРОС для to_cstr() . Есть идеи, как улучшить, или я тоже должен оставить в покое?
- Кен
Комментарии:
1. cpp-next.com/archive/2009/09/your-next-assignment
2. Каждый раз, когда я читаю о новых возможностях языка в C 0x, я очень рад, что перестал писать C до его выпуска 🙂
3. Вы должны создать вторую запись для второго (несвязанного) вопроса. Что касается ответа на этот вопрос, я бы рекомендовал вам полностью удалить макрос, он слишком похож на функцию для его же блага, поскольку он опасен (он возвращает указатель на внутренние элементы временного), скрывая его за тем, что выглядит как вызов функции, скроет опасностьиз
const char* x = to_cstr( 5 );
[эта конструкция неверна, и она была бы без макроса, но, по крайней мере, вы видите код заранее:const char* x = to_string( 5 ).c_str();
гораздо проще подобрать в редакции кода4. Спасибо, Дэвид! Я обновлю свой код в соответствии с вашими рекомендациями.
5. Б. Тайлер: не комментируйте язык, на котором вы не говорите. Здесь нет никаких новых функций.
rvalue
иlvalue
из C.
Ответ №1:
Просто оставьте это в покое, оно и так эффективно. Даже с компиляторами C 03 компилятор оптимизирует копии.
В основном компилятор удостоверяется, что объект в вызывающем коде to to_string
, оператор return of to_string
и оператор return of ss.str()
занимают точно такую же ячейку памяти. Что, в свою очередь, означает, что копий не будет.
Помимо того, что предписывает стандарт, соглашения о вызовах для оператора return функции, которая возвращает по значению объект, который не помещается в регистры во всех известных мне компиляторах 32/64 (включая VS, gcc, intel, suncc), передадут указатель на место в памяти, где функция должна быть возвращена.создайте возвращаемый объект, чтобы код был внутренне преобразован во что-то в строках:
// Not valid C ! Just for illustration purposes
template <typename T>
to_string( uninitialized<string>* res, const Tamp; t ) {
stringstream ss;
ss << t;
stringstream::str( res, amp;ss ); // first argument is return location
// second argument is `this`
}
Ответ №2:
Теперь у меня есть вторая часть моего вопроса. Есть ли способ улучшить это?
#define to_cstr( T ) (to_string( T ).c_str())
Конечно, я хотел бы избежать макросов, если смогу, но если я скопирую и вставлю приведенный выше код шаблона, чтобы вернуть ss.str().c_str() и const char* , временное значение не живет достаточно долго; хотя код, кажется, выполняется, valgrind жалуется (красный свет).
Вы можете заставить компилятор создать для вас временное значение в области вызывающего объекта, чтобы временное время жизни соответствовало времени выражения, в котором создается временное. Вот как:
struct TmpStr {
mutable std::string s;
};
template<typename T>
char const* to_cstr(T value, TmpStr constamp; tmp = TmpStr()) {
tmp.s = to_string(value); // your original function
return tmp.s.c_str(); // tmp lives in the scope of the caller
}
int main() {
printf("%sn", to_cstr(1));
}
Комментарии:
1.
tmp
сохраняется достаточно долго для использованияprintf
, но оно по-прежнему является временным и по-прежнему уничтожается после точки с запятой. Это остается чрезвычайно опасной конструкцией.2. @DennisZickefoose: Вы правы, что с C вы можете отстрелить всю ногу. Однако ваша оценка риска субъективна.