Должен ли я вернуть std:: strings?
Я пытаюсь использовать std::string
вместо char*
когда это возможно, но я беспокоюсь, что могу слишком сильно ухудшить производительность. Это хороший способ возврата строк (без проверки ошибок для краткости)?
std::string linux_settings_provider::get_home_folder() {
return std::string(getenv("HOME"));
}
также, связанный вопрос: при принятии строк в качестве параметров, я должен получить их как const std::string&
или const char*
?
спасибо.
12 ответов:
возвращает строку.
Я думаю, что лучше забор стоит. Пока вы не можете измерить значимую разницу в производительности, я бы сказал, что это микро-оптимизация, которая существует только в вашем воображении.
потребовалось много лет, чтобы получить хорошую абстракции строк в C++. Я не верю, что Bjarne Stroustroup, так известный своим консервативным "только плати за то, что ты используешь", позволил бы очевидному убийце производительности в язык. Высший абстракция-это хорошо.
возвращать строку, как все говорят.
при принятии строк в качестве параметров, я должен получить их как
const std::string&
илиconst char*
?Я бы сказал, Возьмите любые параметры const по ссылке, если только они не достаточно легки, чтобы принимать значение, или в тех редких случаях, когда вам нужен нулевой указатель, чтобы быть допустимым значением ввода "ни один из вышеперечисленных". Эта политика не является специфичной для строк.
неконстантные опорные параметры являются спорными, потому что из вызывающего кода (без хорошей IDE) вы не можете сразу увидеть, передаются ли они по значению или по ссылке, и разница важна. Поэтому код может быть неясным. Для const params это не применяется. Люди, читающие вызывающий код, обычно могут просто предположить, что это не их проблема, поэтому им только иногда нужно будет проверить подпись.
в случае, когда вы собираетесь взять копию аргумента в функцию, ваша общая политика должна быть взять аргумент по значению. Тогда у вас уже есть копия, которую вы можете использовать, и если бы вы скопировали ее в какое-то определенное место (например, элемент данных), вы можете переместить ее (в C++11) или поменять ее (в C++03), чтобы получить ее там. Это дает компилятору наилучшую возможность оптимизировать случаи, когда вызывающий объект передает временный объект.
на
string
в частности, это касается случая, когда ваша функция принимаетstd::string
по значению, и вызывающий указывает в качестве аргумента выражение a строковый литерал илиchar*
указывая на строку с нулевым завершением. Если вы взялиconst std::string&
и скопировал его в функцию, что привело бы к построению двух строк.
стоимость копирования строк по значению зависит от реализации STL, с которой вы работаете:
std:: string в MSVC использует оптимизацию коротких строк, так что короткие строки (
std:: string под GCC использует подсчитанную ссылку реализация: при построении std:: string из char* выделение кучи выполняется каждый раз, но при передаче значения функции счетчик ссылок просто увеличивается, избегая выделения памяти.
В общем, вам лучше просто забыть об этом и вернуть std:: strings по значению, если вы не делаете это тысячи раз в секунду.
re: передача параметров, имейте в виду, что есть стоимость от перехода от тип char*->с std::строки, а не из ходя из СТД::строка->тип char*. В общем, это означает, что вам лучше принять ссылку const на строку std::. Однако лучшим оправданием для принятия const std:: string& в качестве аргумента является то, что тогда вызываемый объект не должен иметь дополнительный код для проверки против null.
кажется, хорошая идея.
Если это не является частью программного обеспечения в реальном времени (например, игры), но регулярное приложение, вы должны быть более чем хорошо.
Это человеческая природа, чтобы беспокоиться о производительности, особенно когда язык программирования поддерживает низкоуровневую оптимизацию. Что мы не должны забывать как программисты, хотя это то, что производительность программы является лишь одной из многих вещей, которые мы можем оптимизировать и восхищаться. В дополнение к скорости программы мы можем найти красоту в нашем собственном исполнении. Мы можем минимизировать наши усилия, пытаясь достичь максимальной визуальной отдачи и интерактивности пользовательского интерфейса. Как вы думаете, это может быть больше мотивации, что беспокоясь о битах и циклах в долгосрочной перспективе... Так что да, возвращайте строку: s. они минимизируют размер вашего кода и ваши усилия, а также делают объем работы, который вы вкладываете, менее удручающим.
в вашем случае оптимизация возвращаемого значения будет иметь место, поэтому std:: string не будет скопирована.
будьте осторожны, когда вы пересекаете границы модуля.
тогда лучше всего возвращать примитивные типы, поскольку типы C++ не обязательно совместимы с двоичными файлами даже в разных версиях одного и того же компилятора.
Я согласен с другими плакатами, что вы должны использовать string.
но знайте, что в зависимости от того, насколько агрессивно ваш компилятор оптимизирует временные параметры, вы, вероятно, будете иметь некоторые дополнительные накладные расходы (по использованию динамического массива символов). (Примечание: хорошей новостью является то, что в C++0a разумное использование ссылок rvalue не потребует оптимизации компилятора, чтобы купить эффективность здесь - и программисты смогут сделать некоторые дополнительные гарантии производительности своего кода без полагаясь на качество компилятора.)
в вашей ситуации, это дополнительные накладные расходы стоит ввести ручное управление памятью? Большинство разумных программистов не согласятся , но если у вашего приложения действительно возникнут проблемы с производительностью, следующим шагом будет профилирование вашего приложения - таким образом, если вы вводите сложность, вы делаете это только после того, как у вас есть веские доказательства того, что это необходимо для повышения общей эффективности.
кто-то упомянул, что возвращаемое значение оптимизация (RVO) здесь неуместна - я не согласен.
стандартный текст (C++03) на этом читает (12.2):
[Начало Стандартной Цитаты]
временные типы классов создаются в различных контекстах: привязка rvalue к ссылке (8.5.3), возврат rvalue( 6.6.3), преобразование, которое создает rvalue (4.1, 5.2.9, 5.2.11, 5.4), выбрасывание исключения (15.1), ввод обработчика (15.3) и в некоторых инициализациях (8.5). [Примечание: срок службы объекты исключения описаны в разделе 15.1. ] Даже когда создание временного объекта избегается (12.8) , все семантические ограничения должны соблюдаться, как если бы временный объект был создан. [Пример: даже если конструктор копирования не вызывается, все семантические ограничения, такие как доступность (пункт 11), должны быть выполнены. ]
[Example: struct X { X(int); X(const X&); ˜X(); }; X f(X); void g() { X a(1); X b = f(X(2)); a = f(a); }здесь реализация может использовать временную конструкцию X (2) перед передачей ее в f () с помощью X конструктор копирования; альтернативно, X (2) может быть построен в пространстве, используемом для хранения аргумента. Кроме того, временный может использоваться для хранения результата f(X(2)) перед копированием его в b с помощью copyconstructor X; альтернативно, результат f () может быть построен в b. с другой стороны, выражение A=f(a) требует временного либо для аргумента a, либо для результата f(a), чтобы избежать нежелательного сглаживания а. ]
[Конец Стандартной Цитаты]
по сути, текст выше говорит, что вы можете полагаться на RVO в ситуациях инициализации, но не в ситуациях назначения. Причина в том, что когда вы инициализируете объект, нет никакого способа, чтобы то, что вы инициализируете, когда-либо могло быть псевдонимом самого объекта (поэтому вы никогда не выполняете самостоятельную проверку в конструкторе копирования), но когда вы выполняете назначение, это может быть.
в вашем коде нет ничего, что по своей сути запрещает RVO - но прочитайте документацию компилятора убедитесь, что вы действительно можете положиться на него, если вам это действительно нужно.
Я согласен с duffymo. Вы должны сначала сделать понятное рабочее приложение, а затем, если есть необходимость, оптимизировать атаку. Именно на этом этапе у вас будет представление о том, где находятся основные узкие места, и вы сможете более эффективно управлять своим временем в создании более быстрого приложения.
Я согласен с @duffymo. Не оптимизируйте, пока вы не измерили, это имеет двойное значение при выполнении микрооптимизации. И всегда: мера до и после вы оптимизировали, чтобы увидеть, если вы на самом деле изменилось к лучшему.