Це тонкіше, ніж інші відповіді. Не існує абсолютного розриву між даними про стек і даними на купі, залежно від того, як ви це оголошуєте. Наприклад:
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 з посиланнями на оцінку rvalue .
У найскладніших ситуаціях з усіх країн ви піднесуть цю ідею до загальної крайності та використовуєте інтелектуальний клас вказівника, такий, shared_ptr
який вже є в tr1. (Хоча я стверджую, що якщо вам це здається потрібним, ви, можливо, переїхали за межі приємного місця застосування Standard C ++.)