2010-07-18 4 views
0

Хорошо, вы, ребята, очень помогли с моим последним вопросом, поэтому я попробую еще один. Это также домашнее задание, и, хотя последний был довольно старым, он был отправлен и ждет, чтобы его отметили. Поэтому, если есть что-то, что меня укусит, это, вероятно, будет эта проблема. Я обфускал имена классов и т. Д., Так как все еще можно отправить задание (для других студентов).istream_iterator утечка памяти

У меня есть класс, единственным членом которого является указатель на объект. Этот класс построен для выделения определенных операций из указателя, который он удерживает в настоящий момент, - Object *o_, который является базовым классом до Object{1, 2, 3, ...}. Теперь я могу сделать следующее без каких-либо утечек памяти или сбоев.

std::vector<ObjectPtr> v; 
v.push_back(ObjectPtr(new Object1(..., ..., ...))); 
v.push_back(ObjectPtr(new Object2(..., ...))); 
v.push_back(ObjectPtr(new Object1(.., .., ..))); 

// Copy Constructor Ptr 
std::vector<ObjectPtr> v2(v); 
// Assignment Operator Ptr 
std::vector<ObjectPtr> v3; 
v3 = v2; 

Все это работает, и утечек памяти нет. Но если я попытаюсь прочитать содержимое из файла с istream_iterator<ObjectPtr>, он начнет течь. ObjectPtr - это единственный класс, обрабатывающий динамическую память, а Object *o_ либо установлен в NULL, либо назначен Object{1, 2, 3, ...}.

Файл для чтения выглядит следующим образом

 
Object1 
... 
... 
Object2 
... 
... 
Object1 
.. 
std::ifstream is("file.txt"); 
std::istream_iterator<ObjectPtr> in(is), end; 
for (; in != end; ++in) 
    cout << *in << "\n"; 

Функция друг в ObjectPtr используется для чтения в этих значениях выглядит

friend istream &operator>>(istream &is, ObjectPtr &op) { 
    std::string tmp; 
    while (std::getline(is, tmp)) { 
     if (tmp == "Object1") { 
      op.o_ = new Object1; 
      return is >> (Object1 &)*(op.o_); // Send it to operator>> for Object1 
     } 
     if (tmp == "Object2") { 
      op.o_ = new Object2; 
      return is >> (Object2 &)*(op.o_); 
     } 
     ... 
    } 
    return is; 
} 

Где-то здесь он начинает unicorning на меня, и мне очень хотелось бы знать, почему.

В двух словах - istream_iterator утечки памяти во время присваивания и конструктор копирования работает должным образом, что приводит меня к мысли, что классы Object{1, 2, 3, 4, ..} построены правильно, и проблема должна быть найдена в operator>>.

ответ

2

Это первое, что происходит со мной. Я не знаю, что ли этот вопрос вы охотитесь за:

friend istream &operator>>(istream &is, ObjectPtr &op) { 
    std::string tmp; 
    while (std::getline(is, tmp)) { 
     if (tmp == "Object1") { 
      op.o_ = new Object1; 

В этой последней строке, что происходит со старым значением в op.o?
Помните, что потоковая передача в объект означает поток в полностью построенный объект, и вам приходится иметь в виду старые данные объекта. (Вот почему часто предпочитают конструкторов с std::istream. Для сложных объектов, сейфов инициализации для объекта, который должен быть изменен в следующий момент.)

ли оператор присваивания или функцию в swap() члена ObjectPtr? Если это так, было бы проще реализовать оператор ввода, построив новый объект и назначив его/заменив его на op.

+0

О, человек .. Вы сделали мой день - удалите op.o_; Спасибо Спасибо спасибо! – citizencane

+0

@citizancane: Обратите внимание, что вам все равно нужно следить за этим членом 'o' во многих других местах. Как насчет назначения? Прописи строительство? Действительно, я предпочел бы реализовать 'operator >>()' в терминах других членов (как я написал в своем ответе), чем дублировать весь этот код вручную, играя с динамически выделенным объектом. – sbi

+0

Думая об этом еще раз, я мог бы даже разделить «ObjectPtr» на два класса, поскольку он (по крайней мере) имеет две вещи: (A) он управляет динамически распределенным объектом и (B) он служит в качестве прокси-сервера при работе с этим объект. Если вы разделите (A) на подходящий класс интеллектуальных указателей, внедрение (B) станет намного проще и чище. – sbi