Мне любопытно, как я начинаю принимать больше идиом повышения и, как представляется, лучшие практики. Интересно, в какой момент мой C++ даже отдаленно похож на C++ прошлых лет, часто встречающийся в типичных примерах и в умах тех, кто не был знаком с «Modern C++»?После того, как вы приняли интеллектуальные указатели boost, есть ли случай, когда вы используете необработанные указатели?
ответ
Только несколько с верхней части моей головы:
- ходовом вокруг в отображенные в памяти файлов.
- Вызов Windows API, в котором вам нужно перераспределить (например, LPBITMAPINFOHEADER).
- Любой код, в котором вы производите произвольную память (VirtualQuery() и т.п.).
- Как раз в любое время вы используете reinterpret_cast <> на указателе.
- Каждый раз, когда вы используете размещение - новое.
Общая тема здесь «любая ситуация, в которой вам нужно обрабатывать кусок памяти как нечто иное, чем ресурс, над которым у вас есть контроль распределения».
В эти дни я почти полностью отказался от использования необработанных указателей. Я даже начал просматривать нашу базу кода для мест, где использовались исходные указатели, и переключил их на вариант интеллектуального указателя. Удивительно, сколько кода я смог удалить, выполнив этот простой акт. Слишком много кода потрачено на управление жизненным циклом необработанных указателей на C++.
Единственные места, где я не использую указатели, - это несколько сценариев взаимодействия с другими кодами, на которых у меня нет контроля.
Я по-прежнему использую регулярные указатели в коде, чувствительном к ресурсам, или другой код, который требует крошечного отпечатка, например, некоторые исключения, где я не могу предположить, что какие-либо данные действительны и также должны предположить, что у меня тоже закончилась память.
Управляемая память почти всегда превосходит необработанную, потому что это означает, что вам не нужно иметь дело с удалением ее в нужном месте, но все же иметь большой контроль над точками конструкции и уничтожения ваших указателей.
О, и есть одно место, чтобы использовать сырые указатели:
boost::shared_ptr<int> ptr(new int);
Если у вас есть кольцевые структуры данных, например, точки В и В точках обратно в А, вы не можете использовать наивности использовать умные указатели для A и B, так как тогда объекты будут освобождены только от дополнительной работы. Чтобы освободить память, вам необходимо вручную очистить интеллектуальные указатели, что примерно так же плохо, как удалить умные указатели.
Возможно, это произойдет не очень часто, но предположим, что у вас есть объект родителя, который имеет интеллектуальные указатели на кучу дочерних объектов. Где-то по пути кому-то нужно найти родителя для ребенка, поэтому они добавляют к ребенку умный указательный элемент, который указывает на родителя. Безмолвно память больше не освобождается.
Требуется некоторая осторожность. Умные указатели не эквивалентны сбору мусора.
Это то, что boost :: weak_ptr для, если оно у вас есть. Таким образом, вы все равно можете использовать интеллектуальные указатели, а не сырые, только не все умные указатели будут shared_ptr. – 2008-12-12 18:13:12
Абсолютное повышение :: weak_ptr - это еще один способ решить круглые проблемы с ссылками, но я думаю, что моя цель по-прежнему сохраняется: вы должны обратить внимание, а не просто слепо использовать любые интеллектуальные указатели, которые у вас есть. – 2008-12-12 18:49:27
Я не использую shared_ptr
почти полностью, потому что я избегаю совместного владения в целом. Поэтому я использую что-то вроде boost::scoped_ptr
для «собственного» объекта, но все остальные ссылки на него будут грубыми указателями. Пример:
boost::scoped_ptr<SomeType> my_object(new SomeType);
some_function(my_object.get());
Но some_function
будет иметь дело с сырым указателем:
void some_function(SomeType* some_obj)
{
assert (some_obj);
some_obj->whatever();
}
я до сих пор используют сырые указатели на устройствах, которые порт ввода-вывода, такие как встроенные системы, где, имеющих смарт-указатель Безразлично» t действительно имеет смысл, потому что вам никогда не понадобится или не сможет delete
.
Я нахожу основное различие между «современным» C++ и старым * материалом - это осторожное использование инвариантов класса и инкапсуляции. Хорошо организованный код, естественно, имеет тенденцию иметь меньше указателей, летающих вокруг. Я почти нервно плаваю в shared_ptrs, так как буду в новостях и удаляю.
Я с нетерпением жду unique_ptr
в C++ 0x. Я думаю, что это уберет несколько (умных) указателей, которые все еще бродят по дикой природе.
* до сих пор, к сожалению, очень распространены
Конечно любое время вы имеете дело с устаревшей библиотеки или API вам необходимо пройти сырой указатель, хотя вы, вероятно, просто извлечь его из смарт-указатель временно.
На самом деле всегда безопасно передавать необработанный указатель на функцию, если функция не пытается сохранить копию указателя в глобальной или членной переменной или попытаться удалить ее. При наличии этих ограничений функция не может повлиять на время жизни объекта, и единственной причиной умного указателя является управление временем жизни объекта.
Я пишу C++, который должен сосуществовать с Objective C (используя Objective C++ для моста). Поскольку объекты C++, объявленные как часть классов Objective C++, не имеют конструкторов или деструкторов, вы не можете их действительно удерживать в интеллектуальных указателях.
Поэтому я стараюсь использовать необработанные указатели, хотя часто с boost :: intrustive_ptr и внутренним количеством ссылок.
Не то, чтобы я сделал это, но вам нужны необработанные указатели для реализации, скажем, связанного списка или графика. Но было бы разумнее использовать std::list<>
или boost::graph<>
.
Я думал, что не было накладных расходов с boost: классы указателей? Разве компилятор не оптимизирует все? – ApplePieIsGood 2008-12-12 18:53:49
Существует не слишком много накладных расходов на классы указателей, но оно должно существовать, а общим указателям нужен счетчик ссылок и связанные с ним механизмы. Я всегда следую правилу 1; сначала профиль, затем оптимизируйте. – coppro 2008-12-12 19:17:36
Не могу придумать один раз из 15 лет программирования на C++, который мне когда-либо понадобился, чтобы явно выделить один int в куче. Массив int: s - другое дело, но тогда всегда есть std :: vector. –
2008-12-21 00:27:33