Вопрос

Я пытаюсь использовать std::string вместо char* когда это возможно, но я боюсь, что могу слишком сильно снизить производительность.Это хороший способ возврата строк (без проверки ошибок для краткости)?

std::string linux_settings_provider::get_home_folder() {
    return std::string(getenv("HOME"));
}

Также сопутствующий вопрос:принимая строки в качестве параметров, должен ли я получать их как const std::string& или const char*?

Спасибо.

Это было полезно?

Решение

Верните строку.

Я думаю, что лучшая абстракция того стоит.Пока вы не сможете измерить существенную разницу в производительности, я бы сказал, что это микрооптимизация, существующая только в вашем воображении.

Чтобы реализовать хорошую строковую абстракцию в C++, потребовалось много лет.Я не верю, что Бьёрн Страустроуп, столь известный своим консервативным изречением «платите только за то, что используете», допустил бы в свой язык явный убийца производительности.Высшая абстракция — это хорошо.

Другие советы

Верните строку, как все говорят.

принимая строки в качестве параметров, должен ли я получать их как const std::string& или const char*?

Я бы посоветовал брать любые константные параметры по ссылке, если только они не достаточно легкие, чтобы их можно было принимать по значению, или в тех редких случаях, когда вам нужен нулевой указатель, чтобы быть допустимым вводом, означающим «ничего из вышеперечисленного».Эта политика не специфична для строк.

Неконстантные ссылочные параметры являются спорными, поскольку из вызывающего кода (без хорошей IDE) нельзя сразу увидеть, передаются ли они по значению или по ссылке, а разница важна.Поэтому код может быть неясным.Для константных параметров это не применимо.Люди, читающие вызывающий код, обычно могут просто предположить, что это не их проблема, поэтому проверять подпись им придется лишь изредка.

В случае, когда вы собираетесь получить копию аргумента функции, ваша общая политика должна заключаться в том, чтобы брать аргумент по значению.Тогда у вас уже есть копия, которую вы можете использовать, и если вы скопировали ее в какое-то определенное место (например, элемент данных), вы можете переместить ее (в C++11) или поменять местами (в C++03) на возьми это там.Это дает компилятору лучшую возможность оптимизировать случаи, когда вызывающая сторона передает временный объект.

Для string в частности, это касается случая, когда ваша функция принимает std::string по значению, а вызывающая сторона указывает в качестве выражения аргумента строковый литерал или char* указывающий на строку, завершающуюся нулем.Если вы взяли const std::string& и скопировал его в функцию, что привело бы к построению двух строк.

Стоимость копирования строк по значению зависит от реализации STL, с которой вы работаете:

  • std::string в MSVC использует оптимизацию коротких строк, поэтому короткие строки (< 16 символов iirc) не требуют выделения памяти (они хранятся внутри самого std::string), а более длинные требуют выделения кучи каждый раз, когда строка копируется.

  • std::string в GCC использует реализацию с подсчетом ссылок:при создании std::string из char* выделение кучи выполняется каждый раз, но при передаче значения в функцию счетчик ссылок просто увеличивается, избегая выделения памяти.

В общем, лучше просто забыть об этом и возвращать std::strings по значению, если только вы не делаете это тысячи раз в секунду.

ре:При передаче параметров имейте в виду, что переход от char*->std::string требует затрат, но не переход от std::string->char*.В общем, это означает, что вам лучше принять константную ссылку на std::string.Однако лучшее оправдание для принятия const std::string& в качестве аргумента состоит в том, что тогда вызываемому абоненту не нужно иметь дополнительный код для проверки vs.нулевой.

Кажется, это хорошая идея.

Если это не часть программного обеспечения реального времени (например, игры), а обычное приложение, все будет более чем хорошо.

Помнить, "Преждевременная оптимизация — корень всех зол"

Человеку свойственно беспокоиться о производительности, особенно когда язык программирования поддерживает низкоуровневую оптимизацию.Однако мы, программисты, не должны забывать, что производительность программы — это лишь одна из многих вещей, которую мы можем оптимизировать и которой можно восхищаться.Помимо скорости программы, мы можем найти красоту в собственном исполнении.Мы можем свести к минимуму наши усилия, пытаясь добиться максимального визуального результата и интерактивности пользовательского интерфейса.Как вы думаете, это может быть большей мотивацией, чем беспокойство о кусочках и циклах в долгосрочной перспективе...Так что да, возвращайте строку:s.Они минимизируют размер вашего кода и ваши усилия, а также делают объем выполняемой вами работы менее удручающим.

В вашем случае будет выполнена оптимизация возвращаемого значения, поэтому std::string не будет скопирован.

Будьте осторожны, пересекая границы модулей.

Тогда лучше всего возвращать примитивные типы, поскольку типы C++ не обязательно двоично совместимы даже в разных версиях одного и того же компилятора.

Я согласен с другими авторами, что вам следует использовать веревку.

Но знайте, что в зависимости от того, насколько агрессивно ваш компилятор оптимизирует временные файлы, у вас, вероятно, возникнут дополнительные накладные расходы (по сравнению с использованием динамического массива символов).(Примечание:Хорошей новостью является то, что в 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 с помощью конструктора копирования X;альтернативно, результат f() может быть создан в b.С другой стороны, выражение a = f (a) требует временного для аргумента a или результата f (a), чтобы избежать нежелательного псевдонима A.]

[Конец стандартной цитаты]

По сути, в приведенном выше тексте говорится, что вы можете полагаться на RVO в ситуациях инициализации, но не в ситуациях назначения.Причина в том, что когда вы инициализируете объект, то, с помощью чего вы его инициализируете, не может быть сопоставлено с самим объектом (именно поэтому вы никогда не выполняете самопроверку в конструкторе копирования), но когда вы это делаете задание, оно могло бы.

В вашем коде нет ничего, что по своей сути запрещало бы RVO, но прочтите документацию по компилятору, чтобы убедиться, что вы действительно можете на него положиться, если он вам действительно нужен.

Я согласен с Даффимо.Сначала нужно сделать понятное работающее приложение, а потом, если есть необходимость, оптимизировать атаку.Именно на этом этапе у вас появится представление о том, где находятся основные узкие места, и вы сможете более эффективно управлять своим временем при создании более быстрого приложения.

Я согласен с @duffymo.Не оптимизируйте, пока не измерите, это вдвойне верно при выполнении микрооптимизации.И всегда:мера до и после вы оптимизировали, чтобы увидеть, действительно ли вы изменили ситуацию к лучшему.

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

Кроме того, вы всегда можете встроить функцию, но большинство оптимизаторов все равно ее исправят.

Если вы передаете ссылку на строку и работаете с этой строкой, вам не нужно ничего возвращать.;)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top