Всех приветствую вот например хочу защитится от повторного вызова конструктора для уже созданного объекта пример Код (Text): typedef char* pChar; class string_t { char *str; size_t len; size_t size; public: string_t(const char *str); }; string_t::string_t(const char *str) { this->len = strlen(str); this->size = this->len + 1; this->str = pChar(malloc(this->size)); strcpy(this->str, str); } int main() { string_t str("content"); new(&str)string_t("new content"); } так вот в итоге теряется старый указатель а проверять сразу неинициализированный объект в конструкторе на предмет был ли создан уже объект нет возможности вернее все последующие то вызовы можно а первый нет как поступить ? я смотрел реализацию класса CString из MFC он тоже при таком использовании начинает терять память потом я посмотрел std::string он этот случай обрабатывает нормально тоесть память не утекает просто присваивается новая строка но не смог разобратся в исходниках стандартного класса чтобы выяснить как он это делает есть идеи ?
> нет возможности вернее все последующие то вызовы можно а первый нет почему? вполне валидное решение добавить проверку а-ля: Код (Text): if (_str) free((void *)_str);
n0name в str при первом вызове все что угодно может быть то что было в стеке или в куче то и будет на что проверять то ? понятно что последующие вызовы констуктора я так смогу проверить но первый непридумаю как
точно. тогда хз. с std::string у тебя работает потому что строки короткие (< 16 символов). Ппроверь на более длинных строрках, результат будет тот же.
и правда а я думал что std::string этим не страдает а он оказывается короткие строки хранит прямо в объекте Код (Text): int main() { std::string str("content"); char *p = pChar(&str); for (size_t i = 0; i < sizeof(std::string); i++) printf("%c", p[i]); } ╠╠╠╠content ╠╠╠╠╠╠╠╠ ☼ Для продолжения нажмите любую клавишу . . . теперь понятно почему он не теряет память на коротких строчках
Зачем два раз конструировать один и тот же объект? Это ошибка программиста, а не дизайна. Но если так хочется, то можно завести статический контейнер объектов(менеджер объектов) и возиться. Хотя непонятно зачем.
Booster да я бы может сразу так и подумал что если кто то так напишет то пусть сам и отвечает но заметил что std::string ведет себя нормально с этого все и началось а тут уже выяснили что std::string тоже не закодирована предвидеть такое использование и корректно реагировать
osox FindAtom / AddAtom Конечно ОСозависимо, но наверняка в nix есть что нибудь подобное, так что можно сделать универсальную обёртку или самому их аналог написать.
Booster Универсальное решение позволяющее определить первый/повторный вызов любого кода (главное правильно алгоритм генерации уникальных идентификаторов продумать). Согласен, что заморачиваться с решением этой задачи здесь нецелесообразно, но если очень хочется то технически решение возможно
Y_Mur Это нужно делать не на уровне всех процессов, а на уровне одного. Менеджер объектов - вот решение.
Booster Менеджер объектов понятие весьма растяжимое В данном случае он вполне может быть самописным аналогом целочисленных win атомов, т.е. таблицей this-ов с функциями поиска/добавления и всё А можно и готовые вин функции использовать, хотя гемороя с ними будет больше чем самому аналог сделать. ЗЫ: Кстати на уровне всех процессов это GlobalAddAtom а не просто AddAtom.
Y_Mur А я про что говорю? Хоть мапа [key->this][val->this]. Никаких атомов не надо. Насчёт локальной таблицы, да ошибся, но всё равно это абсолютно не нужно. ^)
Y_Mur Booster решил что бред огород городить просто не надо так писать вот еще пример в конструктор копий надо вставлять проверку на создание из себя самого например Код (Text): string_t::string_t(const string_t &str) { if (*this != str) // ... else this->string_t() // ... } // ... string_t str = str; а то например mfc::string падает на этом а std::string это обрабатывает вприниципе можно и вставить а можно позволить и упасть а вообще это все провокационный код надеящийся что об этом позаботились что уже отобъет всю охоту так писать у незнакомых типов да и с практической точки зрения это просто выпрашивание непрятностей не более можно сделать почленное копирование так как объект еще не создан мы ничего не теряем но с другой стороны мы можем вызвать конструктор по умолчанию
osox Проверка на самого себя в конструкторе копирования не нужна, так как конструктор вызывается только один раз. Проверка нужна в операторе присваивания.
osox Отвечу на первый пост. У Вас нет повторного вызова конструктора одного и того же объекта, поэтому тут нельзя ничего избежать. Вы вызывали конструктор нового объекта, перезаписывая при этом содержимым нового объекта память старого. С тем же успехом можно было сделать ZeroMemory (&str, sizeof(str)) и удивляться, почему указатель теряется.
l_inc всмысле ? явно видно что просто конструктор вызывается для того же объекта еще раз new ведь в данном случае память не выделяет а просто адрес возвращает нами же ему и переданный Код (Text): int main() { string_t str("content"); new(&str)string_t("new content"); } int main() { 004134E0 55 push ebp 004134E1 8B EC mov ebp,esp 004134E3 83 EC 54 sub esp,54h 004134E6 53 push ebx 004134E7 56 push esi 004134E8 57 push edi string_t str("content"); 004134E9 68 98 78 41 00 push offset string "content" (417898h) 004134EE 8D 4D F4 lea ecx,[str] 004134F1 E8 17 DD FF FF call string_t::string_t (41120Dh) new(&str)string_t("new content"); 004134F6 8D 45 F4 lea eax,[str] 004134F9 50 push eax 004134FA 6A 0C push 0Ch 004134FC E8 40 DB FF FF call operator new (411041h) 00413501 83 C4 08 add esp,8 00413504 89 45 B0 mov dword ptr [ebp-50h],eax 00413507 83 7D B0 00 cmp dword ptr [ebp-50h],0 0041350B 74 12 je main+3Fh (41351Fh) 0041350D 68 88 78 41 00 push offset string "new content" (417888h) 00413512 8B 4D B0 mov ecx,dword ptr [ebp-50h] 00413515 E8 F3 DC FF FF call string_t::string_t (41120Dh) 0041351A 89 45 AC mov dword ptr [ebp-54h],eax 0041351D EB 07 jmp main+46h (413526h) 0041351F C7 45 AC 00 00 00 00 mov dword ptr [ebp-54h],0 } 00413526 8D 4D F4 lea ecx,[str] 00413529 E8 35 DC FF FF call string_t::~string_t (411163h) 0041352E 33 C0 xor eax,eax 00413530 5F pop edi 00413531 5E pop esi 00413532 5B pop ebx 00413533 8B E5 mov esp,ebp 00413535 5D pop ebp 00413536 C3 ret
osox Не понимаю, где Вы в листинге видите, что конструктор для того же объекта. Формально это новый объект. Просто Вы его расположили по тому же адресу, что и предыдущий. Причём в листинге используются "разные" адреса: Для первого объекта конструктору передаётся адрес, взятый через: 004134EE 8D 4D F4 lea ecx,[str] Для второго объекта честно используется адрес, возвращённый new: 00413504 89 45 B0 mov dword ptr [ebp-50h],eax ... 00413512 8B 4D B0 mov ecx,dword ptr [ebp-50h] Так что ИМХО "явно видно" как раз обратное.
l_inc lea ecx,[str]; и то что возвращает new это в точности один и тот же адрес вот код этой версии new Код (Text): inline void *__CRTDECL operator new(size_t, void *_Where) _THROW0() { // construct array with placement at _Where 00401000 55 push ebp 00401001 8B EC mov ebp,esp return (_Where); 00401003 8B 45 0C mov eax,dword ptr [ebp+0Ch] } 00401006 5D pop ebp 00401007 C3 ret
osox Ну и что, что тот же самый адрес? Это ведь Вы расположили второй объект, используя placement new, по тому же адресу. Рассмотрим такой код: Код (Text): class string_t { char *str; size_t len; size_t size; public: string_t(const char *str); }; class Client { size_t budget; size_t credit; char *name; public: Client(const char *name); }; int main() { string_t str("content"); Client *client = new(&str)Client("Vas'a"); } Хотите сказать, что здесь опять вызываются конструкторы одного и того же объекта? Ведь адрес-то один и тот же.