Передача массива символов функции, которая ожидает постоянную ссылку на std::string

#c #arrays #stdstring

#c #массивы #stdstring

Вопрос:

Я допустил ошибку в интерфейсе сокета, который я написал некоторое время назад, и я просто заметил проблему, просматривая код для другой проблемы. Сокет получает строку символов и передает ее в jsoncpp для завершения синтаксического анализа json. Я почти понимаю, что здесь происходит, но у меня не укладывается в голове. Я хотел бы понять, что на самом деле происходит под капотом. Вот минимальный пример:

 #include <iostream>
#include <cstring>

void doSomethingWithAString(const std::string amp;val) {
    std::cout << val.size() << std::endl;
    std::cout << val << std::endl;
}

int main()
{
    char responseBufferForSocket[10000];
    memset(responseBufferForSocket, 0, 10000);

    //Lets simulate a response from a socket connection
    responseBufferForSocket[0] = 'H';
    responseBufferForSocket[1] = 'i';
    responseBufferForSocket[2] = '?';

    // Now lets pass a .... the address of the first char in the array...
    // wait a minute..that's not a const std::stringamp; ... but hey, it's ok it *works*!
    doSomethingWithAString(responseBufferForSocket);

    return 0;
}
  

Приведенный выше код не вызывает никаких очевидных проблем, но я хотел бы исправить его, если есть скрытая проблема. Очевидно, что массив символов преобразуется в строку, но с помощью какого механизма? Я думаю, у меня есть четыре вопроса:

  1. Эта строка преобразуется в стеке и передается по ссылке или она передается по значению?
  2. Используется ли operator= overload? Конструктор «из c-string»? Какой-то другой механизм?
  3. На основе 2 это менее эффективно, чем преобразование в строку явно с использованием конструктора?
  4. Это опасно. 🙂

скомпилирован с помощью g (Ubuntu 5.4.0-6ubuntu1 ~ 16.04.12) 5.4.0 20160609

Ответ №1:

std::string имеет неявный конструктор (т.Е. не помеченный explicit ключевым словом), который принимает const char* параметр и копирует символы до первого '' (поведение не определено, если такого символа не существует в строке). Другими словами, он выполняет копирование исходных данных. На этой странице перегрузка # 5.

const char[] неявно уменьшается до const char* , и вы можете передать временное значение функции, принимающей const ссылочный параметр. Это работает, только если ссылка const , кстати; если вы не можете использовать const , передайте ее по значению.

И поэтому, когда вы передаете const char[] этой функции временный объект типа std::string , создается с использованием этого конструктора и привязывается к параметру. Временное значение будет оставаться активным во время вызова функции и будет уничтожено при ее возврате.

Имея все это в виду, давайте ответим на ваши вопросы:

  1. Он передается по ссылке, но ссылка относится к временному объекту.
  2. Конструктор, поскольку мы создаем объект. std::string также имеет параметр operator= , принимающий const char* значение, но он никогда не используется для неявных преобразований: вам нужно будет явно что-то назначить.
  3. Производительность одинакова, поскольку выполняется тот же код, но вы несете некоторые накладные расходы, потому что данные копируются, а не ссылаются. Если это проблема, используйте std::string_view вместо этого.
  4. Это безопасно до тех пор, пока вы не пытаетесь сохранить ссылку или указатель на параметр дольше, чем вызов функции, потому что впоследствии объект может перестать быть активным (но тогда вы всегда должны помнить об этом при использовании ссылочных параметров). Вам также необходимо убедиться, что передаваемая вами строка C должным образом завершается нулем.

Комментарии:

1. Спасибо за подробный ответ. Обратите внимание, что мой массив не является const , но я не думаю, что это имеет значение, потому что функция принимает постоянную ссылку. Если бы const не был частью параметра функции, все это рухнуло бы. string_view выглядит потрясающе, но мы только начали компилировать с 11, не говоря уже о 14 или 17 .. это произойдет лет через 20 или около того.

2. В этом случае значение const или его отсутствие не имеет значения: char[] распадается на char* и char* неявно преобразуется в const char* , поэтому остальная часть системы работает так, как ожидалось.

Ответ №2:

  1. Преобразована ли эта строка в стеке

Язык не определяет хранение временных объектов, но в данном случае они, вероятно, хранятся в стеке, да.

или это передается по значению?

Аргумент является ссылкой. Следовательно, вы «передаете по ссылке».

  1. Используется ли operator= overload?

Нет. Вы не используете operator= там, так зачем бы это?

Конструктор «из c-string»?

ДА.

  1. На основе 2 это менее эффективно, чем преобразование в строку явно с использованием конструктора?

Нет. Создается объект неявно или явно, не имеет отношения к эффективности.

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

  1. Опасно ли это.

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

Комментарии:

1. Спасибо за информацию. Это очень полезно. Вызываемый мной метод является фиктивной версией библиотеки, которую я использую, поэтому, к сожалению, я пока застрял со строкой.