Надлежащий стек и использование "кучи" в C++?

На основании удаленного ответа я решил свою проблему:

return TypeCars::with('cars')->leftJoin('user_cars', function($join){
    $join->on('user_cars.id', '=', 'type_cars.id');
        $join->on('user_cars.id', '=', DB::raw(1)); 
})
    ->whereNull('user_cars.id')
    ->where('user_cars.id', '=', 1)
    ->get()
    ->toJson();

DB::raw необходимо, чтобы Eloquent не цитировал необработанные значения.

121
задан fredoverflow 13 March 2011 в 09:31
поделиться

8 ответов

Нет, различием между стеком и "кучей" не является производительность. Это - продолжительность жизни: любая локальная переменная в функции (что-либо Вы не делаете malloc () или новый), жизни на стеке. Это уходит, когда Вы возвращаетесь из функции. Если Вы хотите, чтобы что-то жило дольше, чем функция, которая объявила это, необходимо выделить его на "куче".

class Thingy;

Thingy* foo( ) 
{
  int a; // this int lives on the stack
  Thingy B; // this thingy lives on the stack and will be deleted when we return from foo
  Thingy *pointerToB = &B; // this points to an address on the stack
  Thingy *pointerToC = new Thingy(); // this makes a Thingy on the heap.
                                     // pointerToC contains its address.

  // this is safe: C lives on the heap and outlives foo().
  // Whoever you pass this to must remember to delete it!
  return pointerToC;

  // this is NOT SAFE: B lives on the stack and will be deleted when foo() returns. 
  // whoever uses this returned pointer will probably cause a crash!
  return pointerToB;
}

Для более ясного понимания того, каков стек, приезжайте в него от другого конца - а не попытайтесь понять то, что стек делает с точки зрения высокоуровневого языка, ищет "стек вызовов" и "соглашение о вызовах" и видит то, что действительно делает машина, когда Вы вызываете функцию. Память компьютера является просто серией адресов; "куча" и "стек" являются изобретениями компилятора.

240
ответ дан 24 November 2019 в 01:29
поделиться

Я сказал бы:

Хранилище это на стеке, если Вы CAN.

Хранилище это на "куче", если Вы ДОЛЖНЫ.

Поэтому предпочитают стек "куче". Некоторые возможные причины, что Вы не можете сохранить что-то на стеке:

  • Это является слишком большим - на многопоточных программах на 32-разрядной ОС, стек имеет маленькое и фиксированное (во время создания потока, по крайней мере) размер (обычно всего несколько megs. Это - то, так, чтобы можно было создать много потоков, не исчерпывая адресное пространство. Для 64-разрядных программ, или единственный распараллелил (Linux так или иначе) программы, это не главная проблема. В соответствии с 32-разрядным Linux, единственные потоковые программы обычно используют динамические стеки, которые могут продолжать расти, пока они не достигают верхушки.
  • необходимо получить доступ к нему вне объема исходного стекового фрейма - это - действительно главная причина.

возможно, с разумными компиляторами, выделить объекты нефиксированного размера на "куче" (обычно массивы, размер которых не известен во время компиляции).

42
ответ дан 24 November 2019 в 01:29
поделиться

Это более тонко, чем другие ответы предлагают. Нет никакого абсолютного деления между данными по стеку и данными по "куче" на основе того, как Вы объявляете это. Например:

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 функция (и любой сложный тип значения должен иметь один) может служить своего рода rebindable ссылкой на некоторые данные "кучи" под системой, которая гарантирует единственному владельцу тех данных.

Поэтому современный подход C++ к [1 113] никогда , хранят адрес данных "кучи" в явных локальных переменных указателя. Все выделения "кучи" должны быть скрыты в классах.

, Если Вы делаете это, можно думать обо всех переменных в программе, как будто они были простыми типами значения и забывают о "куче" в целом (кроме тех случаев, когда запись нового подобного значению класса обертки для некоторых данных "кучи", которые должны быть необычными).

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

a = b;

подкачивают их как это:

a.swap(b);

, потому что это намного быстрее и это не выдает исключения. Единственное требование - то, что Вам не нужно b, чтобы продолжить содержать то же значение (оно собирается добраться a значение вместо этого, которое было бы повреждено в [1 110]).

оборотная сторона - то, что этот подход вынуждает Вас возвращать значения от функций через выходные параметры вместо фактического возвращаемого значения. Но они фиксируют это в C++ 0x с [1 112] rvalue ссылки .

В самых сложных ситуациях всех, Вы взяли бы эту идею общему экстремальному значению и использовали бы класс интеллектуального указателя такой в качестве [1 111], который уже находится в tr1. (Хотя я утверждал бы, что, если Вам, кажется, нужен он, Вы возможно переместили зону наилучшего восприятия внешнего Стандартного C++ применимости.)

24
ответ дан 24 November 2019 в 01:29
поделиться

Вы также сохранили бы объект на "куче", если она должна использоваться вне объема функции, в которой она создается. Одну идиому, используемую с объектами стека, называют RAII - это включает использование основанного на стеке объекта как обертка для ресурса, когда объект уничтожается, ресурс был бы очищен. Основанные на стеке объекты легче отслеживать то, когда Вы могли бы выдавать исключения - Вы не должны интересоваться удалением основанного на "куче" объекта в обработчике исключений. Поэтому необработанные указатели обычно не используются в современном C++, Вы использовали бы интеллектуальный указатель, который может быть основанной на стеке оберткой для необработанного указателя на основанный на "куче" объект.

6
ответ дан 24 November 2019 в 01:29
поделиться

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

Выделение в "куче" требует нахождения отслеживания блока памяти, которая не является постоянно-разовой операцией (и берет некоторые циклы и наверху). Это может стать медленнее, поскольку память становится фрагментированной, и/или Вы рядом с использованием 100% Вашего адресного пространства. С другой стороны, выделения стека являются постоянно-разовыми, в основном "бесплатными" операциями.

Другая вещь рассмотреть (снова, действительно только важный, если это становится проблемой) состоит в том, что обычно размер стека фиксируется и может быть намного ниже, чем размер "кучи". Таким образом, при выделении больших объектов или многих маленьких объектов Вы, вероятно, хотите использовать "кучу"; если у Вас закончится стековое пространство, то время выполнения бросит сайт номинальное исключение. Не обычно грандиозное предприятие, но другая вещь рассмотреть.

5
ответ дан 24 November 2019 в 01:29
поделиться

Для полноты вы можете прочитать статью Mirok Samek о проблемах использования кучи в контексте встроенного программного обеспечения .

Куча проблем

2
ответ дан 24 November 2019 в 01:29
поделиться

Выбором того, выделить ли на "куче" или на стеке, является тот, который сделан для Вас, в зависимости от того, как Ваша переменная выделяется. При выделении чего-то динамично, с помощью "нового" вызова, Вы выделяете от "кучи". Если Вы выделяете что-то как глобальную переменную, или в качестве параметра в функции она выделяется на стеке.

1
ответ дан 24 November 2019 в 01:29
поделиться

По-моему, существует два решающих фактора

1) Scope of variable
2) Performance.

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

Для улучшения производительности при использовании "кучи" можно также использовать функциональность для создания блока "кучи", и это может помочь в получении производительности вместо того, чтобы выделить каждую переменную в различной ячейке памяти.

0
ответ дан 24 November 2019 в 01:29
поделиться
Другие вопросы по тегам:

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