Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Узнать в конструкторе использовался ли new при создании / 25 сообщений из 32, страница 1 из 2
26.03.2006, 16:51
    #33625822
cap83
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Привет всем ! Вопрос такой .

В конструкторе надо узнать использовался ли new при создании .
Тое

Foo bar;
или Foo * bar= new Foo()

У Страуструпа написано смотри на this указатель . Если this = 0 то первый вариант на самом деле при написании проги на Visual C++ 6.0 VS2005 Builder программа
#include <iostream>
class Foo {
public :
Foo() {
if (this) cout << "B";
else cout <<"A"
}

};

int main ()
{
Foo x; Foo * y = new Foo ();
return 0;
}

результат BB всегда ! Что делать собственно ?
...
Рейтинг: 0 / 0
26.03.2006, 17:10
    #33625839
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Мона попробовать Foo *x=NULL;

Или сравнить адрес &x с адресом стека (это изврат ИМХО
кому это надо?).

Или посмотреть опции компиллера.

P.S. Или я чет не понял.
...
Рейтинг: 0 / 0
26.03.2006, 17:22
    #33625847
cap83
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Не передавать именно надо Foo x; или Foo * x = new Foo() а парится в конструкторе на самом деле простои интересно стало кому верить
...
Рейтинг: 0 / 0
26.03.2006, 18:41
    #33625898
buser
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
авторУ Страуструпа написано смотри на this указатель Самому мне что-то не найти... тоже интересно... Можно точную цитату? Да я как-то у тов-ща о чем-то похожем спрашивал... В этот момент мой рейтинг упал ниже плинтуса :) Зачем если не секрет?
...
Рейтинг: 0 / 0
26.03.2006, 19:47
    #33625939
cap83
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
http://www.unix.org.ua/cpp/gl5_2.htm

5.5.7
....

Конструктор может определить, был ли он вызван операцией new, или нет. Если он вызван new, то указатель this на входе имеет нулевое значение, в противном случае this указывает на пространство, уже выделенное для объекта (например, на стек). Поэтому можно просто написать конструктор, который выделяет память, если (и только если) он был вызван через new. Например:

mytype::mytype(int i)
{
if (this == 0) this = mytype_alloc();
// присваивание членам
};


Эквивалентного средства, которое позволяет деструктору решить вопрос, был ли его объект создан с помощью new, не имеется, как нет и средства, позволяющего ему узнать, вызвала ли его delete, или он вызван объектом, выходящим из области видимости. Если для пользователя это существенно, то он может сохранить где-то соответствующую информацию для деструктора. Другой способ, - когда пользователь обеспечивает, что объекты этого класса размещаются только соответствующим образом. Если удается справиться с первой проблемой, то второй способ интереса не представляет.
Если тот, кто реализует класс, является одновременно и его единственным пользователем, то имеет смысл упростить, исходя из предположений о его использовании. Когда класс разрабатывается для более широкого использования, таких допущений, как правило, лучше избегать.
...
Рейтинг: 0 / 0
26.03.2006, 23:42
    #33626085
buser
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Да... забавно... всётаки это наверное зависит и от компилятора... Хотя и похоже на бред... это бред... т.е. в 80% эта возможность ни кому не нужна... (это рассуждения делетанта коим я являюсь) Спасибо за цитату. :) Ради праздного любопытства взгляните, что написано в MSDN про this. Т.е. объект уже размещён в памяти (см. реализацию new) и хитрый компилятор пихает этот адрес как скрытый аргумент в вызов любой функции... Хорошая тема для обсуждения... Наверное адепты наставят меня на путь истиный...
...
Рейтинг: 0 / 0
27.03.2006, 01:00
    #33626107
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
cap83В конструкторе надо узнать использовался ли new при создании .


Это невозможно. Если у тебя написано в книге Страуструпа (или еще где) проверять this, то книга устаревшая и это давно уже неправда, потому что это понятия до стандарта C++.

Единственный вариант в классе определить динамически выделен объект или нет, это вести пул всех созданных динамически объектов.

1) Заводится статический массив, который содержит список адресов всех объектов данного класса, созданных динамичеки.

2) Переопределяется в данном классе operator new.

3) в operator new каждый созданный экземпляр заносится в этот список динамически созданных объектов

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

5) Надо учитывать особенности переопределения operator new и особенности работы в многопоточной среде (если это нужно), поскольку у вас будут статические данные -- при необходимости их нужно защищать мьютексами или семафорами.
...
Рейтинг: 0 / 0
27.03.2006, 01:07
    #33626109
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
cap83Если он вызван new, то указатель this на входе имеет нулевое значение, в противном случае this указывает на пространство, уже выделенное для объекта (например, на стек). Поэтому можно просто написать конструктор, который выделяет память, если (и только если) он был вызван через new.

Это - еще раз, цитаты из какого-то фуфла из эпохи до стандартизации.
Да, тогда были подобного рода изыски. Но это было в годах примерно 1987

В современном С++ (XXI века)
1) this в конструкторе всегда отличен от нуля и содержит адрес уже выделенного (но возможно еще неполностью сконструированного) объекта.
2) this неявно объявляется как
T * const,
во всех методах, в том числе и в конструкторе и деструкторе, т.е. указателю НЕЛЬЗЯ ПРИСВОИТЬ НОВОЕ ЗНАЧЕНИЕ (нельзя перенести объект в другой адрес).

3) Невозможно определить в конструкторе и деструкторе способ выделения памяти под объект.
...
Рейтинг: 0 / 0
27.03.2006, 09:12
    #33626256
buser
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Ну собственно - что и требовалось доказать... :)
...
Рейтинг: 0 / 0
27.03.2006, 15:36
    #33627466
Сергей Ильич
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
У Мейерса в More Effective C++ есть способ решения этой проблемы. Книжки под рукой нет, но в И-Нете можно поискать. Проблема обсосана многопланово - как запретить создание объекта в куче, как запретить создание объекта везде, кроме кучи и как определить, где создан объект - в стат.памяти, в куче или в стеке.
...
Рейтинг: 0 / 0
27.03.2006, 16:44
    #33627741
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
У Меерса и написано то, о чем написал я. Ну плюс конечно много всяческих подробностей.
...
Рейтинг: 0 / 0
27.03.2006, 17:37
    #33627908
nik_x
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Doc No: N1905=05-0165
Date: 2005-10-19
Reply to: Pete Becker
Dinkumware, Ltd.
petebecker@acm.org

Working Draft, Standard for Programming Language C++

Цитата:

A pointer to objects of type T is referred to as a "pointer to T." [ Example: a pointer to an object of type int is referred
to as "pointer to int " and a pointer to an object of class X is called a "pointer to X." -end example ] Except for
pointers to static members, text referring to "pointers" does not apply to pointers to members. Pointers to incomplete
types are allowed although there are restrictions on what can be done with them (3.9). A valid value of an object pointer
type represents either the address of a byte in memory (1.7) or a null pointer (4.10). If an object of type T is located
at an address A, a pointer of type cv T* whose value is the address A is said to point to that object, regardless of how
the value was obtained. [ Note: for instance, the address one past the end of an array (5.7) would be considered to
point to an unrelated object of the array's element type that might be located at that address. -end note ] The value
representation of pointer types is implementation-defined. Pointers to cv-qualified and cv-unqualified versions (3.9.3)
of layout-compatible types shall have the same value representation and alignment requirements (3.9).

Про это разговор?
...
Рейтинг: 0 / 0
27.03.2006, 17:54
    #33627965
nik_x
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
void * operator new(std :: size_t size , const std :: nothrow_t &) throw ();
5 Effects: Same as above, except that it is called by a placement version of a new-expression when a C++ program
prefers a null pointer result as an error indication, instead of a bad_alloc exception.
6 Replaceable: a C++ program may define a function with this function signature that displaces the default version
defined by the C++ Standard library.
7 Required behavior: Return a non-null pointer to suitably aligned storage (3.7.3), or else return a null pointer.
This nothrow version of operator new returns a pointer obtained as if acquired from the ordinary version. This
requirement is binding on a replacement version of this function.
8 Default behavior:
— Executes a loop: Within the loop, the function first attempts to allocate the requested storage. Whether the
attempt involves a call to the Standard C library function malloc is unspecified.
— Returns a pointer to the allocated storage if the attempt is successful. Otherwise, if the last argument to
set_new_handler() was a null pointer, return a null pointer.
— Otherwise, the function calls the current new_handler (18.4.2.2). If the called function returns, the loop
repeats.
— The loop terminates when an attempt to allocate the requested storage is successful or when a called new_-handler
function does not return. If the called new_handler function terminates by throwing a bad_alloc
exception, the function returns a null pointer.
...
Рейтинг: 0 / 0
27.03.2006, 20:53
    #33628263
onstat-
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
MasterZiv
У Меерса и написано то, о чем написал я. Ну плюс конечно много всяческих подробностей.


Есть дополнение по поводу подробностей


MasterZiv
1) Заводится статический массив, который содержит список адресов всех объектов данного класса, созданных динамичеки.


нужно позаботиться о поведении конструкторов копирования.
Очень злую шутку они могут сыграть.
...
Рейтинг: 0 / 0
27.03.2006, 21:10
    #33628285
cap83
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
авторЭто - еще раз, цитаты из какого-то фуфла из эпохи до стандартизации.
Да, тогда были подобного рода изыски. Но это было в годах примерно 1987

Не в курсах что C++ Бьярн Страустрап придумал ?
...
Рейтинг: 0 / 0
27.03.2006, 23:54
    #33628441
Сергей Ильич
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
onstat- MasterZiv
1) Заводится статический массив, который содержит список адресов всех объектов данного класса, созданных динамичеки.

нужно позаботиться о поведении конструкторов копирования.
Очень злую шутку они могут сыграть.
А там конструкторы и не используются. Там используется абстрактный mixin класс, у которого перегружены operator new и operator delete.
...
Рейтинг: 0 / 0
28.03.2006, 09:04
    #33628655
Gluk (Kazan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Не поленился и глянул в Майерса. Если отбросить детали, сказано, что объект не может сколь нибудь переносимым и надежным образом определить создается ли он в хипе или на стеке.

2 Сергей Ильич

Возможно в книжках нужно читать не только заголовки ???
...
Рейтинг: 0 / 0
28.03.2006, 12:52
    #33629356
Сергей Ильич
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Gluk (Kazan)Не поленился и глянул в Майерса. Если отбросить детали, сказано, что объект не может сколь нибудь переносимым и надежным образом определить создается ли он в хипе или на стеке.

Вранье. Там написано, как определять, факт существования объекта на хипе или в стеке (приведен абстрактный класс HeapTracked).
...
Рейтинг: 0 / 0
28.03.2006, 14:22
    #33629732
Gluk (Kazan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Процитируйте если не затруднит. Просто интересно, что из написанного Вы имеете в виду.
...
Рейтинг: 0 / 0
28.03.2006, 15:19
    #33629956
Сергей Ильич
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Fortunately, C++ gives us exactly what we need in the form of an abstract mixin base class. ¤ Item M27, P48

An abstract base class is a base class that can't be instantiated, i.e., one with at least one pure virtual function. A mixin ("mix in") class is one that provides a single well-defined capability and is designed to be compatible with any other capabilities an inheriting class might provide (see Item E7). Such classes are nearly always abstract. We can therefore come up with an abstract mixin base class that offers derived classes the ability to determine whether a pointer was allocated from operator new. Here's such a class: ¤ Item M27, P49
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
class HeapTracked {                  // mixin class; keeps track of
public:                              // ptrs returned from op. new

  class MissingAddress{};            // exception class; see below

  virtual ~HeapTracked() =  0 ;

  static void *operator new(size_t size);
  static void operator delete(void *ptr);

  bool isOnHeap() const;

private:
  typedef const void* RawAddress;
  static list<RawAddress> addresses;
};
This class uses the list data structure that's part of the standard C++ library (see Item E49 and Item 35) to keep track of all pointers returned from operator new. That function allocates memory and adds entries to the list; operator delete deallocates memory and removes entries from the list; and isOnHeap returns whether an object's address is in the list. ¤ Item M27, P50

Implementation of the HeapTracked class is simple, because the global operator new and operator delete functions are called to perform the real memory allocation and deallocation, and the list class has functions to make insertion, removal, and lookup single-statement operations. Here's the full implementation of HeapTracked: ¤ Item M27, P51
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
// mandatory definition of static class member
list<RawAddress> HeapTracked::addresses;

// HeapTracked destructor is pure virtual to make the
// class abstract (see Item E14). The destructor must still
// be defined, however, so we provide this empty definition.
HeapTracked::~HeapTracked() {}



void * HeapTracked::operator new(size_t size)
{
  void *memPtr = ::operator new(size);  // get the memory

  addresses.push_front(memPtr);         // put its address at
                                        // the front of the list
  return memPtr;
}

void HeapTracked::operator delete(void *ptr)
{
  // get an "iterator" that identifies the list
  // entry containing ptr; see Item 35 for details
  list<RawAddress>::iterator it =
    find(addresses.begin(), addresses.end(), ptr);

  if (it != addresses.end()) {       // if an entry was found
    addresses.erase(it);             // remove the entry
    ::operator delete(ptr);          // deallocate the memory
  } else {                           // otherwise
    throw MissingAddress();          // ptr wasn't allocated by
  }                                  // op. new, so throw an
}                                    // exception

bool HeapTracked::isOnHeap() const
{
  // get a pointer to the beginning of the memory
  // occupied by *this; see below for details
  const void *rawAddress = dynamic_cast<const void*>(this);

  // look up the pointer in the list of addresses
  // returned by operator new
  list<RawAddress>::iterator it =
    find(addresses.begin(), addresses.end(), rawAddress);

  return it != addresses.end();      // return whether it was
}                                    // found
This code is straightforward, though it may not look that way if you are unfamiliar with the list class and the other components of the Standard Template Library. Item 35 explains everything, but the comments in the code above should be sufficient to explain what's happening in this example. ¤ Item M27, P52

The only other thing that may confound you is this statement (in isOnHeap): ¤ Item M27, P53
Код: plaintext
1.
const void *rawAddress = dynamic_cast<const void*>(this);
I mentioned earlier that writing the global function isSafeToDelete is complicated by the fact that objects with multiple or virtual base classes have several addresses. That problem plagues us in isOnHeap, too, but because isOnHeap applies only to HeapTracked objects, we can exploit a special feature of the dynamic_cast operator (see Item 2) to eliminate the problem. Simply put, dynamic_casting a pointer to void* (or const void* or volatile void* or, for those who can't get enough modifiers in their usual diet, const volatile void*) yields a pointer to the beginning of the memory for the object pointed to by the pointer. But dynamic_cast is applicable only to pointers to objects that have at least one virtual function. Our ill-fated isSafeToDelete function had to work with any type of pointer, so dynamic_cast wouldn't help it. isOnHeap is more selective (it tests only pointers to HeapTracked objects), so dynamic_casting this to const void* gives us a pointer to the beginning of the memory for the current object. That's the pointer that HeapTracked::operator new must have returned if the memory for the current object was allocated by HeapTracked::operator new in the first place. Provided your compilers support the dynamic_cast operator, this technique is completely portable.
...
Рейтинг: 0 / 0
28.03.2006, 18:13
    #33630569
buser
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Мдя... Наверное круто... Писать чтонить такое, где подобные "извраты" могут пригодиться (завидую)... Вышеизложенный вариант решения очевиден... Но цитата мене убила (if (this == 0) this = mytype_alloc();).
...
Рейтинг: 0 / 0
29.03.2006, 07:56
    #33631142
Gluk (Kazan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Сергей ИльичFortunately, C++ gives us exactly what we need in the form of an abstract mixin base class. ¤ Item M27, P48
...


Два возражения к приведенному коду:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
class A: public HeapTracked
{ ...
};

// Первое:
A* a = new A[ 10 ];

class B: public A
{ private:
     int Reserved;
  ...
};

// Второе:
B* b = new B;

Цитируемый код не предназначен для определения того, находится ли объект в хипе (это невозможно), он всего лишь позволяет проверить можно ли применять delete. Согласитесь, это не одно и то-же.

Вот что пишет по этому вопросу Майерс парой абзацев выше:

автор
The sad fact is there's not only no portable way to determine whether an object is on the heap, there isn't even a semi-portable way that works most of the time. If you absolutely, positively have to tell whether an address is on the heap, you're going to have to turn to unportable, implementation-dependent system calls, and that's that. As such, you're better off trying to redesign your software so you don't need to determine whether an object is on the heap in the first place. ¤ Item M27, P40
...
As luck would have it, it's easier to determine whether it's safe to delete a pointer than to determine whether a pointer points to something on the heap, because all we need to answer the former question is a collection of addresses that have been returned by operator new. Since we can write operator new ourselves (see Items E8-E10), it's easy to construct such a collection. Here's how we might approach the problem: ¤ Item M27, P43

Вопросы, предложения, пожертвования ???
...
Рейтинг: 0 / 0
29.03.2006, 13:59
    #33632292
Сергей Ильич
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Не понял замечанеие 2. Хочешь сказать, эти опреаторы не наследуются? Мой компилятор их, однако, наследует:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
#include <new>
#include <memory>
#include <iostream>
#include <iomanip>

class Base {
	int _val1;
public:
	static void* operator new(size_t size);
	static void operator delete(void *ptr, size_t size);
	virtual ~Base();
};

void* Base::operator new(size_t size) {
	void* retVal = ::operator new(size);
	std::cout<<std::dec<<size<<" bytes has been allocated. The return value is: 0x"
		<<std::hex<<reinterpret_cast<unsigned long>(retVal)<<"\n";
	return retVal;
}

void Base::operator delete(void *ptr, size_t size) {
	std::cout<<"Deallocating "<<std::dec<<size<<" bytes for the pointer referencing at 0x"
		<<std::hex<<reinterpret_cast<unsigned long>(ptr)<<"\n";
	::operator delete(ptr);
}

Base::~Base() { }

class Derived : public Base {
	int _val2;
public:
	virtual ~Derived();
};

Derived::~Derived() { }

int main(int argc, char **argv) {
	std::auto_ptr<Base> base(new Base);
	std::auto_ptr<Derived> derived(new Derived);
} 

Output:
Код: plaintext
1.
2.
3.
4.
5.
 8  bytes has been allocated. The return value is: 0x321148
 12  bytes has been allocated. The return value is: 0x322640
Deallocating  12  bytes for the pointer referencing at 0x322640
Deallocating  8  bytes for the pointer referencing at 0x321148
Press any key to continue
...
Рейтинг: 0 / 0
29.03.2006, 14:13
    #33632366
Gluk (Kazan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Sorry, конечно я имел в виду другое

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
class B 
{ public:
     B(void): A() {}

  private:
     A a;
};

B* b = new B;
A распределен в хип, но узнать об этом может в исключительно редком случае, когда B наследует HeapTracked и не имеет других членов кроме A.
VMT тоже могут дать жизни в плане совместимости.

По массиву вопросов нет ?
...
Рейтинг: 0 / 0
29.03.2006, 14:48
    #33632602
Сергей Ильич
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Узнать в конструкторе использовался ли new при создании
Вопрос этот философский. Вообще говоря, объект A находится не в куче, а вложен в другой объект - это можно рассматривать как отдельный тип стораджа. Что касается массивов, то можно перегрузить operator new[] - там размер массива известен, следовательно можно зарегистрировать сразу все объекты в той же самой таблице.
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Узнать в конструкторе использовался ли new при создании / 25 сообщений из 32, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]