Почему строковое назначение не оптимизируется, когда длина известна компилятору? - PullRequest
1 голос
/ 01 февраля 2010

Сегодня я поигрался с некоторым временным кодом и обнаружил, что при назначении строкового литерала std :: string он был примерно на 10% быстрее (с короткой 12-символьной строкой, так что, как правило, еще большая разница для больших строк) сделать это с литералом известной длины (используя оператор sizeof), чем нет. (Протестировано только с компилятором VC9, поэтому я думаю, что другие компиляторы могут сделать это лучше).

std::string a("Hello World!");
std::string b("Hello World!", sizeof("Hello World!");//10% faster in my tests

Теперь причина, по которой я подозреваю, заключается в том, что он должен вызывать strlen (VC9 собирается в сборку, которая не является моей сильной стороной, поэтому я не могу быть уверен на 100%), чтобы получить длину строки, затем выполните то же, что и во втором случае. в любом случае.

Учитывая, как долго был std :: string, и как часто встречается первый случай (особенно если вы включаете операторы +, =, + = и т. Д. И эквивалентные методы) в программы реального мира, почему он не оптимизируется первый случай во второй? Это также кажется очень простым, просто сказать, что это объект std :: basic_string и литерал, скомпилировать его так, как если бы оно было написано как b?

Ответы [ 2 ]

4 голосов
/ 01 февраля 2010

Первый не может быть оптимизирован во второй. В первом случае длина строки неизвестна, поэтому ее необходимо вычислить, а во втором вы указываете ее длину, поэтому вычисление не требуется.

И использование sizeof () не имеет значения - оно также рассчитывается во время компиляции. Конструктор, который используется в первом случае:

 string( const char * s );

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

Кроме того, построение строк из строковых литералов в стиле C происходит относительно редко в реальном коде - его просто не стоит оптимизировать. И если вам нужно оптимизировать его, просто перепишите:

while( BIGLOOP ) {
   string s( "foobar" );
   ...
}

как:

string f( "foobar" );
while( BIGLOOP ) {
   string s( f );
   ...
}
2 голосов
/ 01 февраля 2010

Компилятор, несомненно, может сделать что-то подобное, и на самом деле вы можете сделать это самостоятельно:

template<size_t SIZE>
std::string f(const char(&c)[SIZE]) {
    return std::string(c, SIZE);
}

int main() {
    std::string s = f("Hello");
    cout << s;
}

или даже с пользовательским производным типом (хотя нет никаких причин, по которым std :: string не может иметь этот конструктор):

class mystring : public string {
public:
    template<size_t SIZE>
    mystring(const char(&c)[SIZE]) : string(c, SIZE) {}
};

int main() {
    mystring s("Hello");
    cout << s;
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...