Я изучаю С++ с самого начала, и я не получаю тему целых строк.
В чем разница между следующими тремя кодами?
-
std::string s = std::string("foo");
-
std::string s = new std::string("foo");
-
std::string s = "foo";
Я изучаю С++ с самого начала, и я не получаю тему целых строк.
В чем разница между следующими тремя кодами?
std::string s = std::string("foo");
std::string s = new std::string("foo");
std::string s = "foo";
std::string s = std::string("foo");
Создает временный объект std::string
, содержащий "foo" , затем присваивает его s
. (Обратите внимание, что компиляторы могут уклоняться от временной. Временный elison в этом случае явно разрешен стандартом С++.)
std::string s = new std::string("foo");
Это ошибка компилятора. Выражение new std::string("foo")
создает std::string
в свободном хранилище и возвращает указатель на std::string
. Затем он пытается присвоить возвращаемый указатель типа std::string*
на s
типа std::string
. Конструкция класса std::string
предотвращает это, поэтому сбой компиляции.
С++ не является Java. Это не так, как обычно создаются объекты, потому что если вы забудете delete
возвращенный объект std::string
, вы будете утечки памяти. Одним из основных преимуществ использования std::string
является то, что он автоматически управляет базовым буфером строк, поэтому new
- это своего рода поражения этой цели.
std::string s = "foo";
Это по существу то же самое, что и # 1. Он технически инициализирует новую временную строку, которая будет содержать "foo" , а затем присваивает ее s
. Опять же, компиляторы, как правило, удаляют временные (и на самом деле почти все не-глупые компиляторы в настоящее время фактически исключают временные), поэтому на практике он просто создает новый объект с именем s
на месте.
В частности, он вызывает конструктор преобразования в std::string
, который принимает аргумент const char*
. В приведенном выше коде конструктор преобразования должен быть не explicit
, в противном случае это ошибка компилятора. Конструктор преобразования фактически не explicit
для std::string
s, поэтому приведенное выше компилируется.
Вот как обычно инициализируется std::string
. Когда s
выходит за пределы области видимости, объект s
будет уничтожен вместе с базовым буфером строк. Обратите внимание, что следующее имеет тот же эффект (и является другим типичным способом std::string
), в том смысле, что он также создает объект с именем s
, содержащий "foo" .
std::string s("foo");
Однако существует тонкая разница между std::string s = "foo";
и std::string s("foo");
, одна из которых заключается в том, что конструктор преобразования может быть либо explicit
, либо не explicit
в приведенном выше случае.
std::string s = std::string("foo");
Это называется инициализацией копирования. Это функционально то же самое, что и прямая инициализация
std::string s( "foo" );
но первый требует, чтобы конструктор копирования был доступен, а компиляторы могли создать временный объект, но большинство из них вернутся к временной и прямой конструкции s
, содержащей "foo"
.
std::string s = new std::string("foo");
Это не скомпилируется, потому что new
возвращает указатель. Чтобы он работал, вам нужен тип s
как std::string *
. Затем строка динамически выделяет объект std::string
и сохраняет указатель в s
. Вам понадобится delete
, как только вы закончите использовать его.
std::string s = "foo";
Это почти то же самое, что и первое. Это инициализация копирования, но она имеет дополнительное ограничение. Для этого требуется, чтобы класс std::string
содержал конструктор не explicit
, который принимает const char *
. Это позволяет компилятору неявно построить временный объект std::string
. После этого семантика идентична случаю 1.
s
new std::string("foo")
возвращает указатель на некоторую вновь выделенную память.
Чтобы это сработало, вы должны объявить s как указатель на строку std::string* s
.Вы должны использовать третий вариант в большинстве случаев, если не во всех случаях.
1 создаст временную переменную (правую сторону), затем вызовет оператор присваивания, чтобы присвоить значение s
2 создаст экземпляр std::string
в куче и вернет указатель на него и не удастся выполнить назначение, потому что вы не можете назначить указатель на не указательный тип
3 построит std::string и инициализирует его с помощью const char*
В номере 1 вы создаете временную строку, используя конструктор, а затем присваиваете ее s. Номер 2 даже не компилируется. На номер 3 вы создаете новую строку, а затем присваиваете ей значение.