Мой вопрос прост. Когда я использую контейнеры STL, они копируют значение, которое я храню там (при помощи конструктора копии) или нет? Что, если я даю им массив символов (символ *) вместо строкового экземпляра? Как они ведут себя? Гарантируется та информация будет храниться в "куче" вместо системной стопки?
Спасибо за ответы.
Значения в контейнерах 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), а так как вы delete
d после нажатия на этот указатель, то ваш вектор содержит дикий указатель, и ваш код рано или поздно (будем надеяться) аварийно завершает работу.
Которого, кстати, можно было бы избежать, если бы вместо char*s вы использовали строки:
typedef vector<string> strings;
strings myStrings;
myStrings.push_back("Hello, buffer");
Они копируют значение. Большинство (все) контейнеры требуют, чтобы разработан конструктор копирования и оператора назначения.
Если вы даете им CHAR *
, они копируют указатель, а не значение, на который не указал. Поэтому тогда это будет ваша ответственность, чтобы убедиться, что сама строка не разрушается, пока она все еще используется, и разрушается, когда он больше не нужен.
Они всегда делают копии. Если вы создадите вектор вектор
, то он будет скопировать char *
, вы нажимаете в него. Однако он не будет скопировать строку символов указывать на точку указателя. Если эта строка была динамически выделена, у вас, вероятно, утечка, поэтому вектор
обычно бесконечно предпочтительнее.
Они всегда копируют, когда вы их вставляете. Если вы дадите им указатель, они скопируют указатель. Данные, на которые указывает указатель, не затрагиваются. Обратите внимание: не рекомендуется помещать необработанные указатели в контейнеры stl, потому что их легко потерять и потерять память. Контейнеры STL не были разработаны, чтобы помочь вам с необработанными указателями. Если вы хотите использовать указатели в контейнерах STL, рассмотрите возможность использования shared_ptr из boost, чтобы обернуть их.
Рассмотрим следующее:
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 внутри вектора, чтобы убедиться, что динамически выделяемая память будет освобождена только тогда, когда на нее больше нет ссылок.
Вы уже получили ряд ответов, указывающих на то, что когда вы помещаете данные в контейнер, они помещаются туда по значению, так что то, что попадает в контейнер - это копия ваших исходных данных.
Есть одно исключение из этого правила: std::list
имеет член сплайса splice
, который позволяет вам вставлять часть (или все) одного списка в другой список. В этом случае данные обычно перемещаются, а не копируются -- по крайней мере, как правило, сращивание происходит с помощью манипуляций с указателями, поэтому узлы, которые были в одном списке, переносятся в другой список.
Исключение составляет тот случай, когда два списка используют различные типы аллокаторов. В этом случае, я считаю, что сплайсинг должен выделить новые узлы, скопировать данные, а затем освободить старые узлы. Опять же, это довольно непонятный угловой случай - большинство людей никогда не реализуют свои собственные типы аллокаторов.