Как использовать строку C ++ в структуре, когда malloc () - той же структуры? - PullRequest
15 голосов
/ 05 августа 2010

Я написал следующий пример программы, но он зависает с segfault. Кажется, проблема в использовании malloc и std::string s в структуре.

#include <iostream>
#include <string>
#include <cstdlib>

struct example {
 std::string data;
};

int main() {
 example *ex = (example *)malloc(sizeof(*ex));
 ex->data = "hello world";
 std::cout << ex->data << std::endl;
}

Я не могу понять, как заставить это работать. Любые идеи, если даже можно использовать malloc() и std::string с?

Спасибо, Бода Цидо.

Ответы [ 5 ]

26 голосов
/ 05 августа 2010

Вы не можете malloc класс с нетривиальным конструктором в C ++.То, что вы получаете от malloc, является блоком raw памяти, который не содержит правильно построенный объект.Любые попытки использовать эту память в качестве «реального» объекта потерпят неудачу.

Вместо malloc -ing объекта используйте new

example *ex = new example;

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

void *ex_raw = malloc(sizeof(example));
example *ex = new(ex_raw) example;

Форма new, использованная выше, имеет видназывается "размещение нового".Однако в вашем случае нет необходимости во всех этих хитростях.

4 голосов
/ 05 августа 2010

Для class или struct, таких как example, правильный ответ - использовать new, а не malloc() для выделения экземпляра. Только operator new знает, как вызывать конструкторы для struct и его членов. Ваша проблема вызвана тем, что строковый член еще не был создан.

Однако, есть редкие случаи, когда важно, чтобы определенный участок памяти действовал так, как если бы он содержал экземпляр класса. Если у вас действительно есть такой случай, то есть вариант operator new, который позволяет указать местоположение объекта. Это называется «новое размещение» и должно использоваться с большой осторожностью.

void *rawex = malloc(sizeof(example));  // allocate space
example ex = new(rawex) example();      // construct an example in it
ex->data = "hello world";               // use the data field, not no crash
// time passes
ex->~example();                         // call the destructor
free(rawex);                            // free the allocation

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

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

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

3 голосов
/ 05 августа 2010

Выделение памяти с помощью malloc не вызывает никаких конструкторов. Не смешивать распределение в стиле C с объектами C ++ .Они плохо играют вместе.Вместо этого используйте оператор new для выделения объектов в коде C ++:

example *ex = new example;

Это более умный код, и он вызовет конструктор std::string::string() для инициализации строки, которая исправит наблюдаемый вами segfault.,И не забудьте удалить его, когда закончите, чтобы освободить память и вызвать соответствующие деструкторы:

delete ex;
2 голосов
/ 05 августа 2010

Проблема в том, что malloc не вызывает конструктор example.Поскольку string обычно представляется как указатель на стек, он устанавливается равным нулю, и вы разыменовываете нулевой указатель.Вам нужно использовать new вместо.

0 голосов
/ 05 августа 2010

вы не должны использовать

пример * ex = (пример *) ТаНос (SizeOf (* ех));

потому что возвращаемый размер sizeof (* ex) равен размеру long или размеру int, что связано с разным окружением компиляции. Вы можете использовать код следующим образом:

пример * ex = (пример *) ТаНос (SizeOf (пример));

...