Должен ли я централизовать все вызовы new / delete для одного класса? - PullRequest
3 голосов
/ 18 сентября 2011

В настоящее время все мои объекты управляют собственной памятью, обычно выделяя с помощью new в своих конструкторах и используя delete в своих деструкторах.Пока это работает, но количество классов, которые используют произвольные объемы памяти, растет.Тот факт, что new по сути является «запросом», также беспокоит меня, поскольку в этих объектах нет кода для обработки, когда мне говорят «нет», и я не хочу полагаться на обработку исключений, если мне это не нужно.

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

  • Является ли использование выделения памяти в небольших классах достаточно большой проблемой, чтобы беспокоиться об этом?

  • Могу ли я по-прежнему использовать контейнеры STL и заставлять их использовать предоставленную мной кучу?

Заранее спасибо!

Ответы [ 5 ]

4 голосов
/ 18 сентября 2011

Могу ли я по-прежнему использовать контейнеры STL и заставлять их использовать предоставленную мной кучу?

Контейнеры STL принимают пользовательские распределители:

http://en.wikipedia.org/wiki/Allocator_(C%2B%2B)#Custom_allocators

Вот ветка со ссылками на примеры:

Неопровержимые примеры пользовательских распределителей C ++?

Это выгодно с точки зрения производительности ...?

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

Если вы можете разбить вашу программу на функциональный уровень и получить реалистичнуюСценарии для каждого случая, вам не нужно, чтобы вся ваша программа работала для этого.Но помните, что время, потраченное на оптимизацию, - это время, которое можно потратить на тестирование или кодирование новых функций :) Делайте то, что нужно, и не более ...

Является ли использование распределения памяти в небольших классах достаточно большимне хотите ли беспокоиться об этом?

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

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

3 голосов
/ 18 сентября 2011

Могу ли я по-прежнему использовать контейнеры STL и заставлять их использовать предоставленную мной кучу?

Да, посмотрите STL распределители .

Полезно ли с точки зрения производительности полностью экранировать все вызовы, которые выделяют память, одному классу, который обрабатывает каждое выделение памяти в куче, возможно, выделяя большие порции за раз и используя новое размещение для раздачи ссылок?

Это в основном то, что делает хорошая реализация malloc или new. Я не рекомендую делать это самостоятельно, если ситуация не является очень критичной для производительности, а все остальное было оптимизировано. Зачем? Потому что хорошее и продуманное управление памятью очень сложно даже без ошибок, не говоря уже об оптимизации работы.

Является ли использование выделения памяти в небольших классах достаточно большой проблемой, чтобы беспокоиться об этом?

Это зависит от того, программируете ли вы кофемашину или игровое устройство с 16 КБ памяти, возможно, но на обычном настольном компьютере или ноутбуке, вероятно, нет. Также помните, что стек очень быстрый (выделение и доступ), в то время как куча намного хуже при распределении и немного (не очень уверена в этом TBH) при использовании, поэтому в повседневных ситуациях вы предпочитаете стек.

3 голосов
/ 18 сентября 2011

Я не совсем уверен, что понимаю вашу проблему здесь. Тем не менее, использование контейнеров STL в C ++ 03 с вашей пользовательской кучей будет сложной задачей, так как распределители считаются без сохранения состояния. Кроме того, почему вы не хотите полагаться на обработку исключений? Знаете ли вы, что существует новая версия no_throw?

Редактировать: Не новая версия new вызывается так: new (std::nothrow) Type[size];. Если распределение завершится неудачно, он вернет нулевой указатель (0) вместо броска std::bad_alloc.

2 голосов
/ 18 сентября 2011

Вы говорите, что вызываете new в своих конструкторах ... Это действительно необходимо?Я имею в виду, вместо этого ...

class A{
    std::vector<int>* v;
    A( int vectorSize ){
       v = new std::vector<int>( vectorSize, 0 );
    }
    ~A(){
       delete v;
    }
};

... всегда лучше сделать это:

class A{
    std::vector<int> v;
    A( int vectorSize ):
       v( vectorSize, 0 ){
    }
};

Таким образом, вы избегаете использования кучи.Вы должны использовать кучу только тогда, когда у вас нет другого выбора.

Помимо этого, как говорили другие, написание вашего пользовательского распределителя является очень сложной задачей и должно выполняться только в критическом сценарии производительности

2 голосов
/ 18 сентября 2011

Я делал это раньше, и вот мой опыт:

  1. Это может очень быстро запутаться. Тем более, что теперь вы берете распределение памяти в свои руки и вам приходится иметь дело с такими вещами, как фрагментация и повторный вход.
  2. Однако я видел повышение производительности на по сравнению с 20% из-за возможности обойти издержки ОС.

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

EDIT:

На основании вашего комментария, вот обновление. Вам действительно не нужно иметь дело с созданием распределителя. Вероятно, вы можете просто указать все выделения памяти для вашего пользовательского класса. Затем ваш пользовательский класс будет вызывать malloc() или new и перехватывать любое возвращаемое значение NULL или исключение.

(хотя потребуется некоторая работа, чтобы заменить каждый new своим malloc().)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...