Мне сказали, что следующий код имеет неопределенное поведение до C ++ 20:
int *p = (int*)malloc(sizeof(int));
*p = 10;
Это правда?
Аргументом было то, что время жизни int
объекта не начинается до присвоения ему значения ( P0593R6 ). Для устранения проблемы new
следует использовать размещение:
int *p = (int*)malloc(sizeof(int));
new (p) int;
*p = 10;
Неужели нам действительно нужно вызывать конструктор по умолчанию, который является тривиальным для запуска жизненного цикла объекта?
В то же время код не имеет неопределенного поведения на чистом C. Но что, если я выделю int
код на C и использую его в коде C ++?
// C source code:
int *alloc_int(void)
{
int *p = (int*)malloc(sizeof(int));
*p = 10;
return p;
}
// C++ source code:
extern "C" int *alloc_int(void);
auto p = alloc_int();
*p = 20;
Это все еще неопределенное поведение?
c++
malloc
undefined-behavior
c++20
anton_rh
источник
источник
int
? Нет. Дляstd::string
? Да.int
тоже да. Просто на практике это не вызовет проблем, если вы этого не сделаете. Ведьstd::string
это, очевидно, вызовет проблемы.int *p = (int*)malloc(sizeof(int)); p = new(p) int;
? Однажды я понял, что не присвоение результата размещения new также может привести к фатальным последствиям (хотя это может выглядеть немного глупо).Ответы:
Да. Технически говоря, не входит в состав:
int *p = (int*)malloc(sizeof(int));
на самом деле создает объект типа
int
, поэтому разыменованиеp
- это UB, поскольку там нет фактическогоint
.Нужно ли использовать объектную модель C ++, чтобы избежать неопределенного поведения до C ++ 20? Да. Может ли компилятор причинить вред, если вы этого не сделаете? Не то, чтобы я в курсе.
Да. До C ++ 20 вы по-прежнему нигде не создавали
int
объект, так что это UB.источник
int
в примере было получено хранилище нужного размера и выравнивания -int
там начинается время жизни объекта.Да, это был УБ. Список способов
int
существования может быть перечислен, и ни один из них не применим, если только вы не считаете, что malloc является акаузальным.Многие считали, что это недостаток стандарта, но маловажный, потому что оптимизация, выполненная компиляторами C ++ вокруг этого конкретного бита UB, не вызывала проблем с этим вариантом использования.
Что касается второго вопроса, C ++ не определяет, как взаимодействуют C ++ и C. Итак, все взаимодействие с C - это ... UB, иначе говоря, поведение не определено стандартом C ++.
источник
extern "C"
синтаксис.gcc -fno-strict-aliasing
, или MSVC по умолчанию). Сказать, что «реализация определена» потребует, чтобы все реализации C ++ определили какой-то способ взаимодействия с некоторой реализацией C, поэтому имеет смысл полностью оставить на усмотрение реализации, хотят они делать что-то подобное или нет.