Disseram-me que o código a seguir tem comportamento indefinido até C ++ 20:
int *p = (int*)malloc(sizeof(int));
*p = 10;
Isso é verdade?
O argumento foi que o tempo de vida do int
objeto não é iniciado antes da atribuição do valor a ele ( P0593R6 ). Para resolver o problema, o posicionamento new
deve ser usado:
int *p = (int*)malloc(sizeof(int));
new (p) int;
*p = 10;
Precisamos realmente chamar um construtor padrão que seja trivial para iniciar a vida útil do objeto?
Ao mesmo tempo, o código não tem comportamento indefinido em C. puro. Mas, e se eu alocar um int
em código C e usá-lo em código 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;
Ainda é um comportamento indefinido?
c++
malloc
undefined-behavior
c++20
anton_rh
fonte
fonte
int
? Não. Parastd::string
? Sim.int
, também sim. Só que não causará problemas na prática se você não fizer isso. Poisstd::string
, obviamente, causará problemas.int *p = (int*)malloc(sizeof(int)); p = new(p) int;
? Uma vez percebi que não atribuir o resultado da colocação new pode causar efeitos fatais também (embora possa parecer um pouco bobo).Respostas:
Sim. Tecnicamente falando, nenhuma parte de:
int *p = (int*)malloc(sizeof(int));
na verdade, cria um objeto do tipo
int
, portanto, a desreferenciaçãop
é UB, pois não há nenhum objeto realint
ali.Você precisa seguir o modelo de objeto C ++ para evitar comportamento indefinido pré-C ++ 20? Sim. Algum compilador realmente causará danos se você não fizer isso? Não que eu saiba.
Sim. Antes do C ++ 20, você ainda não criava um
int
objeto em nenhum lugar, então este é o UB.fonte
int
no exemplo - a vida útil doint
objeto começa aí.Sim, foi UB. A lista de maneiras pelas quais um
int
pode existir foi enumerada e nenhuma se aplica a ela, a menos que você mantenha que malloc é acausal.Foi amplamente considerado uma falha no padrão, mas de baixa importância, porque as otimizações feitas pelos compiladores C ++ em torno daquele bit específico de UB não causaram problemas com aquele caso de uso.
Quanto à 2ª questão, C ++ não determina como C ++ e C interagem. Portanto, toda interação com C é ... UB, também conhecido como comportamento indefinido pelo padrão C ++.
fonte
extern "C"
sintaxe.gcc -fno-strict-aliasing
, ou MSVC por padrão). Dizer "implementação definida" exigiria que todas as implementações C ++ definissem alguma maneira na qual interoperem com alguma implementação C, então faz sentido deixar totalmente para a implementação, quer queiram fazer algo parecido ou não.