Поведение контейнеров C++

Мой вопрос прост. Когда я использую контейнеры STL, они копируют значение, которое я храню там (при помощи конструктора копии) или нет? Что, если я даю им массив символов (символ *) вместо строкового экземпляра? Как они ведут себя? Гарантируется та информация будет храниться в "куче" вместо системной стопки?

Спасибо за ответы.

6
задан Rusty Horse 2 February 2010 в 21:02
поделиться

6 ответов

Значения в контейнерах STL хранятся на складе. Если у вас есть такой вектор:

class BigObject
{
...
};

vector<BigObject> myObjs;
myObjs.push_back(obj1);
myObjs.push_back(obj2);
...

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

То же самое верно и в случае вектора указателей, например vector -- но разница здесь в том, что значение, которое является копией, - это указатель, а не строка, на которую он указывает. Так что если у вас есть:

vector<char*> myStrings;
char* str = new char[256];     // suppose str points to mem location 0x1234 here
sprintf(str, "Hello, buffer");
myStrings.push_back(str);
delete [] str;

...то вектор получит копию указателя. Полученный указатель будет иметь то же самое значение (0x1234), а так как вы deleted после нажатия на этот указатель, то ваш вектор содержит дикий указатель, и ваш код рано или поздно (будем надеяться) аварийно завершает работу.

Которого, кстати, можно было бы избежать, если бы вместо char*s вы использовали строки:

typedef vector<string> strings;
strings myStrings;
myStrings.push_back("Hello, buffer");
7
ответ дан 8 December 2019 в 13:46
поделиться

Они копируют значение. Большинство (все) контейнеры требуют, чтобы разработан конструктор копирования и оператора назначения.

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

5
ответ дан 8 December 2019 в 13:46
поделиться

Они всегда делают копии. Если вы создадите вектор вектор , то он будет скопировать char * , вы нажимаете в него. Однако он не будет скопировать строку символов указывать на точку указателя. Если эта строка была динамически выделена, у вас, вероятно, утечка, поэтому вектор обычно бесконечно предпочтительнее.

3
ответ дан 8 December 2019 в 13:46
поделиться

Они всегда копируют, когда вы их вставляете. Если вы дадите им указатель, они скопируют указатель. Данные, на которые указывает указатель, не затрагиваются. Обратите внимание: не рекомендуется помещать необработанные указатели в контейнеры stl, потому что их легко потерять и потерять память. Контейнеры STL не были разработаны, чтобы помочь вам с необработанными указателями. Если вы хотите использовать указатели в контейнерах STL, рассмотрите возможность использования shared_ptr из boost, чтобы обернуть их.

1
ответ дан 8 December 2019 в 13:46
поделиться

Рассмотрим следующее:

where abs(some_float_field) - 2.18 < 0.001
-121--2341746-

Это не прямой ответ на ваш вопрос, а скорее трюк Scala. Для интерполяции последовательностей в Scala используется xml:

val id = 250
val value = "some%"
<s>select col1 from tab1 where id > {id} and name like {value}</s>.text
// res1: String = select col1 from tab1 where id > 250 and name like some%

Eric.

-121--2301569-

Кроме того, если вы не хотите накладных расходов на копирование целых объектов и не любите головные боли, связанные с использованием указателей, вы можете использовать boost::shared_ptr внутри вектора, чтобы убедиться, что динамически выделяемая память будет освобождена только тогда, когда на нее больше нет ссылок.

0
ответ дан 8 December 2019 в 13:46
поделиться

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

Есть одно исключение из этого правила: std::list имеет член сплайса splice, который позволяет вам вставлять часть (или все) одного списка в другой список. В этом случае данные обычно перемещаются, а не копируются -- по крайней мере, как правило, сращивание происходит с помощью манипуляций с указателями, поэтому узлы, которые были в одном списке, переносятся в другой список.

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

1
ответ дан 8 December 2019 в 13:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: