c ++ использование нового ключевого слова в функции write () функции folly queue [duplicate]

Если все остальное не удается, перекомпилируйте.

Недавно я смог избавиться от нерешенной внешней ошибки в Visual Studio 2012, просто перекомпилировав нарушивший файл. Когда я перестроил, ошибка исчезла.

Это обычно происходит, когда две (или более) библиотеки имеют циклическую зависимость. Библиотека A пытается использовать символы в B.lib и библиотеке B пытается использовать символы из A.lib. Ничего не существует для начала. Когда вы пытаетесь скомпилировать A, шаг ссылки завершится неудачно, потому что он не может найти B.lib. A.lib будет сгенерирован, но не будет dll. Затем вы компилируете B, который будет успешным и сгенерирует B.lib. Повторная компиляция A теперь будет работать, потому что теперь найден B.lib.

345
задан CharlesB 4 November 2013 в 13:24
поделиться

22 ответа

Размещение new позволяет вам создать объект в уже выделенной памяти.

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

Devex дает хороший пример :

Стандартный C ++ также поддерживает оператор размещения new, который строит объект в предварительно выделенном буфере. Это полезно при создании пула памяти, сборщика мусора или просто в том случае, когда безопасность производительности и исключений является первостепенной (нет опасности сбоя распределения, поскольку память уже выделена, а построение объекта в предварительно выделенном буфере занимает меньше времени) :

char *buf  = new char[sizeof(string)]; // pre-allocated buffer
string *p = new (buf) string("hi");    // placement new
string *q = new string("hi");          // ordinary heap allocation

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

Освобождение места размещения new

Вы не должны освобождать все объекты, которые используют буфер памяти. Вместо этого вы должны удалить [] только исходный буфер. Затем вам придется вручную вызвать деструкторов ваших классов вручную. Для хорошего предложения по этому вопросу см. FAQ по Stroustrup: Есть ли «удаление места размещения» ?

321
ответ дан danijar 1 September 2018 в 02:02
поделиться

Используется std::vector<>, потому что std::vector<> обычно выделяет больше памяти, чем objects в vector<>.

7
ответ дан Andreas Magnusson 1 September 2018 в 02:02
поделиться

Вот использование киллера для конструктора на месте C ++: выравнивание с линией кэша, а также другие полномочия из двух границ. Вот мой сверхбыстрый алгоритм выравнивания указателя на любую мощность 2-х границ с 5-ти или менее однотактными инструкциями :

/* Quickly aligns the given pointer to a power of two boundary IN BYTES.
@return An aligned pointer of typename T.
@brief Algorithm is a 2's compliment trick that works by masking off
the desired number in 2's compliment and adding them to the
pointer.
@param pointer The pointer to align.
@param boundary_byte_count The boundary byte count that must be an even
power of 2.
@warning Function does not check if the boundary is a power of 2! */
template <typename T = char>
inline T* AlignUp(void* pointer, uintptr_t boundary_byte_count) {
  uintptr_t value = reinterpret_cast<uintptr_t>(pointer);
  value += (((~value) + 1) & (boundary_byte_count - 1));
  return reinterpret_cast<T*>(value);
}

struct Foo { Foo () {} };
char buffer[sizeof (Foo) + 64];
Foo* foo = new (AlignUp<Foo> (buffer, 64)) Foo ();

Теперь не это просто положил улыбку на твоем лице (:-). I ♥♥♥ C ++ 1x

1
ответ дан Cale 1 September 2018 в 02:02
поделиться

Мы используем его с пользовательскими пулами памяти. Просто эскиз:

class Pool {
public:
    Pool() { /* implementation details irrelevant */ };
    virtual ~Pool() { /* ditto */ };

    virtual void *allocate(size_t);
    virtual void deallocate(void *);

    static Pool::misc_pool() { return misc_pool_p; /* global MiscPool for general use */ }
};

class ClusterPool : public Pool { /* ... */ };
class FastPool : public Pool { /* ... */ };
class MapPool : public Pool { /* ... */ };
class MiscPool : public Pool { /* ... */ };

// elsewhere...

void *pnew_new(size_t size)
{
   return Pool::misc_pool()->allocate(size);
}

void *pnew_new(size_t size, Pool *pool_p)
{
   if (!pool_p) {
      return Pool::misc_pool()->allocate(size);
   }
   else {
      return pool_p->allocate(size);
   }
}

void pnew_delete(void *p)
{
   Pool *hp = Pool::find_pool(p);
   // note: if p == 0, then Pool::find_pool(p) will return 0.
   if (hp) {
      hp->deallocate(p);
   }
}

// elsewhere...

class Obj {
public:
   // misc ctors, dtors, etc.

   // just a sampling of new/del operators
   void *operator new(size_t s)             { return pnew_new(s); }
   void *operator new(size_t s, Pool *hp)   { return pnew_new(s, hp); }
   void operator delete(void *dp)           { pnew_delete(dp); }
   void operator delete(void *dp, Pool*)    { pnew_delete(dp); }

   void *operator new[](size_t s)           { return pnew_new(s); }
   void *operator new[](size_t s, Pool* hp) { return pnew_new(s, hp); }
   void operator delete[](void *dp)         { pnew_delete(dp); }
   void operator delete[](void *dp, Pool*)  { pnew_delete(dp); }
};

// elsewhere...

ClusterPool *cp = new ClusterPool(arg1, arg2, ...);

Obj *new_obj = new (cp) Obj(arg_a, arg_b, ...);

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

50
ответ дан Don Wakefield 1 September 2018 в 02:02
поделиться

Голова: BINGO! Вы получили это полностью - это именно то, для чего он идеально подходит. Во многих встроенных средах внешние ограничения и / или сценарий общего использования заставляют программиста отделять выделение объекта от его инициализации. Скомпонованный вместе, C ++ называет это «экземпляр»; но всякий раз, когда действие конструктора должно быть явно вызвано без динамического или автоматического распределения, размещение нового - это способ сделать это. Это также идеальный способ найти глобальный объект C ++, привязанный к адресу аппаратного компонента (I / O с памятью) или для любого статического объекта, который по какой-либо причине должен находиться по фиксированному адресу.

12
ответ дан dorcsssc 1 September 2018 в 02:02
поделиться

Я использовал его для построения объектов, выделенных в стеке через alloca ().

бесстыдный плагин: я написал о нем здесь .

20
ответ дан Ferruccio 1 September 2018 в 02:02
поделиться

Я использовал его для создания класса Variant (т. е. объекта, который может представлять одно значение, которое может быть одним из нескольких разных типов).

Если все поддерживаемые типы значений по классу Variant являются типами POD (например, int, float, double, bool), тогда достаточно тегированного объединения C-стиля, но если вы хотите, чтобы некоторые из типов значений были объектами C ++ (например, std :: string), Функция C union не будет выполняться, поскольку типы данных, отличные от POD, не могут быть объявлены как часть объединения.

Поэтому вместо этого я выделяю массив байтов, который достаточно велик (например, sizeof (the_largest_data_type_I_support)) и использует размещение new для инициализации соответствующего объекта C ++ в этой области, когда для параметра Variant установлено значение этого типа. (И размещение удаляется заранее, если вы, конечно, переключаясь с другого типа данных, отличного от POD)

10
ответ дан Jeremy Friesner 1 September 2018 в 02:02
поделиться

Смотрите файл fp.h в проекте xll в http://xll.codeplex.com Он решает проблему «необоснованного chumminess с компилятором» для массивов, которые любят переносить свои размеры вокруг с ними.

typedef struct _FP
{
    unsigned short int rows;
    unsigned short int columns;
    double array[1];        /* Actually, array[rows][columns] */
} FP;
3
ответ дан Keith A. Lewis 1 September 2018 в 02:02
поделиться

Это может быть удобно при использовании разделяемой памяти, среди других применений ... Например: http://www.boost.org/doc/libs/1_51_0/doc/html/interprocess/synchronization_mechanisms.html# interprocess.synchronization_mechanisms.conditions.conditions_anonymous_example

5
ответ дан kralyk 1 September 2018 в 02:02
поделиться

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

6
ответ дан Martin Beckett 1 September 2018 в 02:02
поделиться

Я видел, что он использовался в качестве незначительного взлома производительности для указателя «динамического типа» (в разделе «Под капотом»):

Но вот хитроумный трюк, который я использовал для получения быстрой производительности для небольших типов: если поддерживаемое значение может помещаться внутри void *, я фактически не хочу выделять новый объект, я принудительно вставляю его в сам указатель, используя новое место размещения.

6
ответ дан Max Lybbert 1 September 2018 в 02:02
поделиться

Полезно, если вы создаете ядро ​​- где вы помещаете код ядра, который вы читаете с диска или в pagetable? Вы должны знать, куда прыгать.

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

Я также считаю, что в некоторых реализациях STL используется новое размещение, например std :: vector. Таким образом, они выделяют место для 2 ^ n элементов и не нуждаются всегда в realloc.

7
ответ дан mstrobl 1 September 2018 в 02:02
поделиться

Одно место, через которое я столкнулся, находится в контейнерах, которые выделяют смежный буфер, а затем заполняют его объектами по мере необходимости. Как уже упоминалось, std :: vector может это сделать, и я знаю, что некоторые версии MFC CArray и / или CList сделали это (потому что именно там я впервые столкнулся с ним). Метод перераспределения буфера - очень полезная оптимизация, а размещение нового - это почти единственный способ построить объекты в этом сценарии. Он также иногда используется для создания объектов в блоках памяти, выделенных вне вашего прямого кода.

Я использовал его в аналогичной емкости, хотя он часто не возникает. Это полезный инструмент для инструментария C ++.

4
ответ дан Nick 1 September 2018 в 02:02
поделиться

Это также полезно, если вы хотите повторно инициализировать глобальные или статически распределенные структуры.

Старый способ C использовал memset(), чтобы установить все элементы в 0. Вы не можете сделать это в C ++ из-за vtables и настраиваемых конструкторов объектов.

Поэтому я иногда использую следующие

 static Mystruct m;

 for(...)  {
     // re-initialize the structure. Note the use of placement new
     // and the extra parenthesis after Mystruct to force initialization.
     new (&m) Mystruct();

     // do-some work that modifies m's content.
 }
8
ответ дан nimrodm 1 September 2018 в 02:02
поделиться

Механизмы сценариев могут использовать его в собственном интерфейсе для выделения собственных объектов из скриптов. Для примера см. Angelscript (www.angelcode.com/angelscript).

4
ответ дан Raindog 1 September 2018 в 02:02
поделиться

Размещение new также очень полезно при сериализации (скажем, с boost :: serialization). В 10 лет c ++ это только второй случай, когда мне нужно новое место для размещения (третий, если вы включаете интервью :)).

8
ответ дан RichardBruce 1 September 2018 в 02:02
поделиться

Я думаю, что это не было подчеркнуто каким-либо ответом, но еще один хороший пример и использование для нового места размещения - это сокращение фрагментации памяти (с помощью пулов памяти). Это особенно полезно для встроенных и высокодоступных систем. В этом последнем случае это особенно важно, потому что для системы, которая должна работать 24/365 дней, очень важно не иметь фрагментации. Эта проблема не имеет ничего общего с утечкой памяти.

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

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

Я видел это на практике специально для VoxWorks RTOS, поскольку его система распределения памяти по умолчанию сильно страдает от фрагментации. Поэтому выделение памяти с помощью стандартного метода new / malloc было в основном запрещено в проекте. Все резервирования памяти должны поступать в выделенный пул памяти.

7
ответ дан rkachach 1 September 2018 в 02:02
поделиться

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

6
ответ дан Steve Fallows 1 September 2018 в 02:02
поделиться

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

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

Это, конечно, не для слабонервных, но именно поэтому они делают для него синтаксис угловатый.

26
ответ дан T.E.D. 1 September 2018 в 02:02
поделиться

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

Возьмите контейнеры наподобие unordered_map, vector или deque. Все они выделяют больше памяти, чем минимально требуется для вставленных вами элементов, чтобы избежать необходимости распределения кучи для каждой отдельной вставки. Давайте используем vector в качестве простейшего примера.

Когда вы это делаете:

vector<Foo> vec;

// Allocate memory for a thousand Foos:
vec.reserve(1000);

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

Allocation! = Construction, Freeing! = Destruction

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

Должно быть разделение между этими идеями, чтобы избежать излишнего вызова конструкторов и деструкторов излишне левым и правым, и поэтому стандартная библиотека разделяет идею std::allocator (которая не создает или не уничтожает элементы, когда он выделяет / освобождает память *) вдали от используемых им контейнеров, которые вручную создают элементы, используя размещение новых и вручную уничтожая элементы, используя явные вызовы деструкторов.

  • Ненавижу дизайн std::allocator, но это другой предмет, о котором я не буду говорить. : -D

Так или иначе, я, как правило, очень сильно его использую, так как я написал несколько стандартных контейнеров C ++ общего назначения, которые нельзя было построить в условия существующих. Среди них была небольшая реализация векторов, которую я построил пару десятилетий назад, чтобы избежать распределения кучи в обычных случаях и эффективного управления памятью (не выделяет один узел за раз). В обоих случаях я не мог реализовать их с использованием существующих контейнеров, поэтому мне пришлось использовать placement new, чтобы избежать излишнего вызова конструкторов и деструкторов на ненужные вещи слева и справа.

Естественно, если вы когда-нибудь работаете с помощью пользовательских распределителей для выделения объектов по отдельности, например, в виде бесплатного списка, вы также обычно хотели бы использовать placement new, как это (основной пример, который не беспокоит безопасность исключений или RAII):

Foo* foo = new(free_list.allocate()) Foo(...);
...
foo->~Foo();
free_list.free(foo);
4
ответ дан Team Upvote 1 September 2018 в 02:02
поделиться

Это полезно, если вы хотите отделить выделение от инициализации. STL использует новое размещение для создания элементов контейнера.

43
ответ дан Tim Cooper 1 September 2018 в 02:02
поделиться

Как правило, размещение нового используется, чтобы избавиться от стоимости распределения «нормального нового».

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

5
ответ дан xtofl 1 September 2018 в 02:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: