2015-02-20 1 views
0

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

list<MyObject> l; 

У меня также есть метод, который возвращает указатель на один из этих объектов, если она существует, или nullptr иначе.

MyObject* get(int x) { 
    for (std::list<MyObject>::iterator it = l.begin(); it != l.end(); ++it) { 
     if (it->X == x) { 
      return &(*it); 
     } 
    } 
    return nullptr; 
} 

Если я получаю() указатель на элемент, и в то время как я использую его, он получает стерта из другого потока, указатель становится недействительным, и странные вещи случаются :)

То, что я хотел знать, есть ли способ вернуть какой-либо особый вид указателя в get(), так что, если я вызываю стирание на элементе и этот элемент все еще ссылается, его память не будет выпущена до тех пор, пока указатель на нее не будет вне сферы действия.

Я рассмотрел использование ссылки, но мне нужна возможность возврата nullptr на get, поэтому я могу проверить у вызывающего, если возврат действительно был действительным объектом.

Может ли кто-нибудь предложить лучший способ сделать это, чтобы избежать этих проблем с памятью?

+4

Список 'shared_ptr' будет лучше для ваших нужд. –

ответ

2

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

Некоторые Рекомендации:

  • Используйте всегда, как по умолчанию, std::vector
  • Если можно использовать C++ 11 используют стандартный shared_ptr для долевой собственности, если нет, то используйте повышение версии.
  • Используйте заголовок algorithm столько, сколько сможете (в этом случае find_if - это правильный вариант).

Вы также должны попытаться использовать алгоритм поиска конкретного элемента. Вот некоторые примеры кода:

#include <algorithm> 
#include <iostream> 
#include <vector> 
#include <memory> 

struct MyObject { 
    int X; 
    MyObject(int x_value) : X(x_value) {} 
}; 

using element_t = std::shared_ptr<MyObject>; 

std::vector<element_t> l{ 
    std::make_shared<MyObject>(3), std::make_shared<MyObject>(4), 
    std::make_shared<MyObject>(5), std::make_shared<MyObject>(6), 
    std::make_shared<MyObject>(7), std::make_shared<MyObject>(8)}; 

element_t get(int x) { 
    auto it = std::find_if(std::begin(l), std::end(l), 
          [x](const element_t& elem) { return elem->X == x; }); 

    element_t found; 
    if (it != std::end(l)) { 
     found = *it; 
    } 
    return found; 
} 

int main() { 
    auto f1 = get(6); 
    if (f1) { 
     std::cout << "encontrado " << f1->X << std::endl; 
    } else { 
     std::cout << "6 no se encontro" << std::endl; 
    } 

    auto f2 = get(10); 
    if (f2) { 
     std::cout << "encontrado " << f2->X << std::endl; 
    } else { 
     std::cout << "10 no se encontro" << std::endl; 
    } 

    return 0; 
} 
+0

Спасибо, это одна из новых возможностей C++, которая меня забирает, чтобы установить – NetVipeC

+0

. Я не использую вектор, так как список удаляется в случайных позициях, а удаление выполняется быстрее, чем на векторе. это можно сделать и в списке? Я никогда не использовал shared_ptr, я буду изучать его. – BlunT

+0

Могу ли я вернуть null shared_ptr? – BlunT

1

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

Интеллектуальных указатели избегут недопустимого доступа к данным, но у них есть все виды более или менее скрытых проблем

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

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

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

+0

На самом деле я предпочитаю не использовать shared_ptr и unique_ptr, так как память и скорость очень важны, поэтому у меня будет другой подход к моему текущему дизайну, пытаясь синхронизировать все в том месте, где у меня есть эта конкретная проблема. спасибо за головы :) – BlunT

+0

'unique_ptr' не имеет накладных расходов. Это просто заставляет вас явно передавать право собственности, что делает более надежным дизайн без каких-либо затруднений. –

Смежные вопросы