В браузерах кроме IE необходимо использовать маленький объект флэш-памяти управлять буфером обмена, например,
Используйте идиому RAII везде, где можете
Используйте интеллектуальные указатели, например std :: auto_ptr, где это необходимо. (не используйте auto_prt ни в одной из стандартных коллекций, так как это не будет работать так, как вы думаете)
По возможности избегайте создания объектов динамически. Программисты, пришедшие из Java и других подобных языков, часто пишут такие вещи, как:
string * s = new string( "hello world" );
, когда они должны были написать:
string s = "hello world";
Точно так же они создают коллекции указателей, когда они должны создавать коллекции значений. Например, если у вас есть такой класс:
class Person {
public:
Person( const string & name ) : mName( name ) {}
...
private:
string mName;
};
Вместо того, чтобы писать код вроде:
vector <Person *> vp;
или даже:
vector <shared_ptr <Person> > vp;
, вместо этого используйте значения:
vector <Person> vp;
Вы можете легко добавить к такому вектору:
vp.push_back( Person( "neil butterworth" ) );
и все память как для Person, так и для вектора управляется за вас. Конечно, если вам нужен набор полиморфных типов, вы должны использовать (умные) указатели
В 1) RAII, идея состоит в том, чтобы удаление происходило автоматически, если вы поймете, что думаете: «Я только что позвонил по новому, мне нужно не забыть где-то вызвать delete», тогда вы делаете что-то не так . Удаление должно быть а) автоматическим или б) помещаться в dtor (и какой dtor должен быть очевиден).
On 2) Скрытие значений по умолчанию. Выявление недобросовестных копий по умолчанию и т. Д. Может быть кошмаром, проще всего избежать их, скрывая их. Если у вас есть общий «корневой» объект, от которого все наследуется (может быть удобно для отладки / профилирования в любом случае), здесь скрываются значения по умолчанию, тогда, когда что-то пытается назначить / скопировать наследующий класс, компилятор отключает, потому что ctor и т. Д. Не доступно в базовом классе.
Минимизируйте вызовы new, используя контейнеры STL для хранения ваших данных.
Основные шаги делятся на два:
Во-первых, имейте в виду, что каждое новое требует удаления. Итак, когда вы используете оператор new, вы лучше понимаете, что этот объект будет делать, как он будет использоваться и как будет управляться его время жизни.
Во-вторых, убедитесь, что вы никогда не перезаписываете указатель. Вы можете сделать это, используя класс интеллектуальных указателей вместо необработанных указателей, но если вы действительно убедитесь, что никогда не используете его с неявным преобразованием. (пример: используя библиотеку MSXML, я создал интеллектуальный указатель CCOMPtr для хранения узлов, чтобы получить узел, который вы вызываете методом get_Node, передавая адрес интеллектуального указателя, у которого был оператор преобразования, который возвращал базовый тип указателя. К сожалению , это означало, что, если интеллектуальный указатель уже содержал данные, данные этого элемента будут перезаписаны, что приведет к утечке предыдущего узла).
Я думаю, что в этих двух случаях возможна утечка памяти. Если вы используете только интеллектуальный указатель напрямую - никогда не позволяя раскрывать его внутренние данные, вы в безопасности от последней проблемы. Если вы оберните весь свой код, использующий new и delete, в класс (то есть с использованием RAII), тогда вы вполне защищены и от первого.
Избежать утечек памяти в C ++ очень просто, если вы сделаете это.
Я всегда использую std :: auto_ptr
, когда мне нужно создать новый объект в куче.
std::auto_ptr<Foo> CreateFoo()
{
return std::auto_ptr<Foo>(new Foo());
}
Даже если вы вызовете
CreateFoo()
, утечки не произойдет.
Two simple rules of thumb:
delete
explicitly (outside a RAII class, that is). Every memory allocation should be the responsibility of a RAII class which calls delete in the destructor.new
explicitly. If you do, you should immediately wrap the resulting pointer in a smart pointer, which takes ownership of the allocation, and works as above.In your own RAII classes, two common pitfalls are:
std::vector
has to handle this, during push_back
for example. It might cause the vector to resize, which means 1) a memory allocation which may throw, and 2) all the existing elements have to be copied, each of which may throw. An algorithm like std::sort
has to deal with it too. It has to call a user-supplied comparer, which could potentially throw too! if that happens, is the sequence left in a valid state? Are temporary objects destructed cleanly?If you handle the above two cases in your RAII classes, it is pretty much impossible for them to leak memory. И если вы используете классы RAII для обертывания всех выделений ресурсов (выделения памяти, дескрипторы файлов, подключения к базе данных и любые другие типы ресурсов, которые должны быть получены и освобождены), тогда ваше приложение не сможет утечки памяти.
Убедитесь, что общая память, созданная вашим приложением, освобождена, если ее больше никто не использует, очистите отображенные в памяти файлы ...
По сути, убедитесь, что вы очищаете любой тип ресурса, который прямо или косвенно создает ваше приложение. Дескрипторы файлов - это только один из типов ресурсов, которые ваше приложение может использовать во время выполнения.
если вы рекурсивно создадите какое-либо дерево или граф в своем коде для своей структуры данных, возможно, вы съедите всю вашу память.
Существуют инструменты статического анализа кода, которые делают подобные вещи; Википедия - хорошее место для начала поиска. По сути, помимо осторожности и выбора правильных контейнеров, вы не можете дать никаких гарантий относительно написанного вами кода - отсюда и необходимость в таких инструментах, как valgrind и gdb.
Incorporate valgrind unit and system testing early in your development cycle and use it consistantly.
I'm with Glen and jalf regarding RAII at every opportunity.
IMHO you should aim to write completely delete-free code. The only explicit "delete"s should be in your smart pointer class implementations. If you find yourself wanting to write a "delete", go and find an appropriate smart pointer type instead. If none of the "industry standard" ones (boost's etc) fit and you find yourself wanting to write some bizzare new one, chances are your architecture is broken or at the least there will be maintenance difficulties in future.
I've long held that explicit "delete" is to memory management what "goto" is to flow control. More on this in this answer.