Это более тонко, чем предлагают другие ответы. Нет абсолютного разрыва между данными в стеке и данными в куче в зависимости от того, как вы их объявляете. Например:
std::vector<int> v(10);
В теле функции, которая объявляет vector
(динамический массив) из десяти целых чисел в стеке. Но хранилище, управляемое vector
, не находится в стеке.
Ах, но (другие ответы предполагают) время жизни этого хранилища ограничено временем жизни самого vector
, которое здесь основано на стеке, поэтому нет никакой разницы в том, как оно реализовано - мы можем только обращаться с ним как основанный на стеке объект с семантикой значения.
Не так. Предположим, что функция была:
void GetSomeNumbers(std::vector<int> &result)
{
std::vector<int> v(10);
// fill v with numbers
result.swap(v);
}
Таким образом, все, что имеет функцию swap
(и любой тип комплексного значения должен иметь такую функцию), может служить своего рода повторяемой ссылкой на некоторые данные кучи в системе, которая гарантирует одного владельца этих данных.
Поэтому современный подход C ++ состоит в том, чтобы никогда не хранить адрес данных кучи в переменных-пустых локальных указателях. Все выделения кучи должны быть скрыты внутри классов.
Если вы сделаете это, вы можете думать о всех переменных в вашей программе так, как будто они являются простыми типами значений, и полностью забыть о куче (за исключением случаев, когда вы пишете новый класс-оболочку, подобную значению, для некоторых данных кучи, что быть необычным).
Вам просто нужно сохранить один специальный бит знаний, чтобы помочь вам оптимизировать: где это возможно, вместо присвоения одной переменной другой, например:
a = b;
поменяйте их местами так:
a.swap(b);
потому что это намного быстрее и не вызывает исключений. Единственное требование - вам не нужно, чтобы b
продолжал удерживать то же значение (вместо этого он получит значение a
, которое будет сброшено в a = b
).
Недостатком является то, что этот подход заставляет вас возвращать значения из функций через выходные параметры вместо фактического возвращаемого значения. Но они исправляют это в C ++ 0x с ссылочными значениями .
В самых сложных ситуациях вы можете довести эту идею до крайности и использовать класс интеллектуальных указателей, такой как shared_ptr
, который уже находится в tr1. (Хотя я бы сказал, что если вам это нужно, вы, возможно, выйдете за пределы привлекательного места применения Standard C ++.)