Может C ++, класс определяет, является ли это на стеке или куче?

Я имею

class Foo {
....
}

Есть ли способ для Фу быть в состоянии выделить:

function blah() {
  Foo foo; // on the stack
}

и

function blah() {
  Foo foo* = new Foo(); // on the heap
}

Я хочу, чтобы Фу был в состоянии сделать разные вещи в зависимости от того, ассигновано ли это на Стеке или Куче.

Править:

Alof людей спросили меня, «почему делают это?»

Ответ:

Я использую касательно - посчитанный GC прямо сейчас. Однако я хочу иметь способность управлять отметкой & зачисткой также. Для этого я должен пометить ряд указателей «корня» - это указатели на стеке. Таким образом, для каждого класса, я хотел бы знать, являются ли они в стеке или в куче.

37
задан anon 13 January 2010 в 06:26
поделиться

10 ответов

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

Почему вы думаете, почему вам нужно сделать это?

Я обычно находим это потому, что разработчики хотят удалить или не удалять объект на основе того, где он был выделен, но это то, что обычно должно быть оставлено на клиенте вашего кода а не сам код вашего кода.


Обновление:

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

Тем не менее, я не уверен, что это просто простая возможность перехватить новое / удаление для класса, поскольку могут быть ситуации, когда удалить не вызывается и, поскольку Mark / Sweep полагается на ссылок , вам нужно иметь возможность перехватить задания указателя для его работы правильно.

Вы думали о том, как вы собираетесь справиться с этим?

Классический пример:

myobject *x = new xclass();
x = 0;

не приведет к удалению вызова.

Кроме того, как вы обнаружите тот факт, что указатель к одному из ваших экземпляров находится на стеке? Перехват новых и удаление может позволить вам хранить, является ли сам объект стеком или куча, но я в потере от того, как вы скажете, где указатель будет назначен, особенно с помощью кода, как:

myobject *x1 = new xclass();  // yes, calls new.
myobject *x2 = x;             // no, it doesn't.
10
ответ дан 27 November 2019 в 04:48
поделиться

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

1
ответ дан 27 November 2019 в 04:48
поделиться

Требуемая команда называется ConvertFrom-CSV . Синтаксис показан ниже.

NAME
    ConvertFrom-CSV

SYNOPSIS
    Converts object properties in comma-separated value (CSV) format into CSV
    versions of the original objects.

SYNTAX
    ConvertFrom-CSV [[-Delimiter] <char>] [-InputObject] <PSObject[]> [-Header <string[]>] [<CommonParameters>]
    ConvertFrom-CSV -UseCulture [-InputObject] <PSObject[]> [-Header <string[]>] [<CommonParameters>]
-121--4780352-

Мета-вопрос, задаваемый паксом, задается вопросом «зачем вы хотите это сделать».

Теперь при условии, что вы делаете это по «уважительной причине» (возможно, просто любопытство), можно получить такое поведение, переопределяя операторы new и delete, но не забудьте переопределить все варианты 12, включая:

новый, удалите, новый никакой бросок, не удалите бросок, новое множество, удалите множество, новое множество никакой бросок, удалите множество никакой бросок, новое размещение, размещение удаляет, размещение новое множество, размещение удаляет множество.

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

Это своего рода боль, так какое же поведение вы хотели?

-121--1282608-

Как упоминалось выше, необходимо управлять распределением объекта с помощью перегруженного нового оператора. Обратите внимание на две вещи, однако, сначала оператор «placement new», который инициализирует ваш объект внутри буфера памяти, предварительно выделенного пользователем; Во-вторых, ничто не мешает пользователю просто поместить произвольный буфер памяти в ваш тип объекта:

char buf[0xff]; (Foo*)buf;

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

Опять же, как упоминалось выше, вы действительно спрашиваете подробности решения («как»), когда вы должны спросить о первоначальной проблеме, для которой вы разработали это решение («почему»).

3
ответ дан 27 November 2019 в 04:48
поделиться

Ответ нет, нет стандартного / портативного способа сделать это. Хаки с участием перегрузки нового оператора, как правило, имеют отверстия. Хаки, которые зависят от проверки адресов указателя, являются определенными ОС и в реализации Heap, и могут измениться с будущими версиями ОС. Вам может быть комфортно с этим, но я бы не построил какую-либо систему вокруг этого поведения.

Я бы начал смотреть на разные способы достичь вашей цели - возможно, вы можете иметь совершенно другой тип, чтобы служить «root» в вашей схеме или требовать пользователя (правильно) аннотировать стек выделенных типов, как таковые Специальный конструктор.

8
ответ дан 27 November 2019 в 04:48
поделиться

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

Вы должны, однако, рассмотреть, если дифференцировка между двумя типами памяти действительно необходимо изнутри класса. Наличие объекта ведет себя по-разному в зависимости от того, где он хранится звучит, как рецепт катастрофы, если вы не осторожны!

3
ответ дан 27 November 2019 в 04:48
поделиться

Мета-вопрос, заданный pax, "зачем вам это нужно", скорее всего, вы получите более информативный ответ.

Предположим, что вы делаете это "по уважительной причине" (возможно, просто любопытно), можем получить такое поведение, переопределив операторы new и delete, но не забудьте переопределить все 12 вариантов, включая:

new, delete, new no throw, delete no throw, new array, delete array, new array no throw, delete array no throw, placement new, placement delete, placement new array, placement delete array.

Одно можно сделать, поместив это в базовый класс и извлечь из этого пользу.

Это своего рода заноза, так какое же поведение вы хотели изменить?

1
ответ дан 27 November 2019 в 04:48
поделиться

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

Если возможно, проверьте явные данные. Если f.eks сдаст значение null вместо реального значения, тест, скорее всего, пройдет по неправильной причине.

Тестирование с помощью Arg.Is.Anything должно быть сделано тщательно и когда вы действительно не заботитесь о параметре, как в AssertWasNotCalled.

-121--2975533-
Arg<string>.Matches(arg => you got the argument here...);

ОБНОВЛЕНИЕ:

Чтобы получить второй аргумент, сделанный при первом вызове метода Foo на _ FakeSomething :

string someArg = null;
var args = _fakeSomething.GetArgumentsForCallsMadeOn(
    x => x.Foo(0, 0), 
    x => x.IgnoreArguments()
);
var int = (int)args[0][1];
-121--2975532-

Нет, это не может быть сделано надежно или разумно.

Можно определить, когда объекту назначается new , перегружая new .

Но что тогда, если объект построен как член класса, а класс-владелец выделен в куче?

Вот третий пример кода, чтобы добавить к двум у вас есть:

class blah {
  Foo foo; // on the stack? Heap? Depends on where the 'blah' is allocated.
};

Как насчет статических/глобальных объектов? Как бы вы могли отличить их от стека/кучи?

Вы могли бы посмотреть на адрес объекта и использовать его, чтобы определить, находится ли он в пределах диапазона, определяющего стек. Однако размер стека может быть изменен во время выполнения.

Таким образом, лучший ответ заключается в том, что «существует причина , по которой GC mark & sweep не используются с C++». Если требуется правильный сборщик мусора, используйте другой язык, который его поддерживает.

С другой стороны, большинство опытных программистов C++ обнаруживают, что нуждается в сборщике мусора практически исчезает, когда вы узнаете необходимые методы управления ресурсами ( RAI ).

2
ответ дан 27 November 2019 в 04:48
поделиться

Возможно, если вы сравниваете значение «это» с текущим значением указателя стека. Если это

Попробуйте это (используя GCC в X86-64):

#include <iostream>

class A
{
public:
    A()
    {
        int x;

        asm("movq %1, %%rax;"
            "cmpq %%rsp, %%rax;"
            "jbe Heap;"
            "movl $1,%0;"
            "jmp Done;"
            "Heap:"
            "movl $0,%0;"
            "Done:"
            : "=r" (x)
            : "r" (this)
            );

        std::cout << ( x ? " Stack " : " Heap " )  << std::endl; 
    }
};

class B
{
private:
    A a;
};

int main()
{
    A a;
    A *b = new A;
    A c;
    B x;
    B *y = new B;
    return 0;
}

Это должно выводить:

Stack 
Heap 
Stack 
Stack 
Heap
4
ответ дан 27 November 2019 в 04:48
поделиться

Более прямым и менее навязчивым методом был бы поиск указателя на картах областей памяти (таких как /proc//maps). Каждому потоку выделена область в стеке. Статические и глобальные переменные будут жить в .bss section, константы в rodata или const сегменте и так далее.

4
ответ дан 27 November 2019 в 04:48
поделиться

Способ хакки:

struct Detect {
   Detect() {
      int i;
      check(&i);
   }

private:
   void check(int *i) {
      int j;
      if ((i < &j) == ((void*)this < (void*)&j))
         std::cout << "Stack" << std::endl;
      else
         std::cout << "Heap" << std::endl;
   }
};

Если объект был создан на стеке, то он должен жить где-то в направлении переменных стека внешних функций. Обычно куча вырастает с другой стороны, так что стек и куча будут встречаться где-то посередине.

(Есть точно такие системы, где это не сработало бы)

.
18
ответ дан 27 November 2019 в 04:48
поделиться
Другие вопросы по тегам:

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