Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Existence of objects created in C functions

It has been established (see below) placement new is required to create objects

int* p = (int*)malloc(sizeof(int));
*p = 42;  // illegal, there isn't an int

Yet that is a pretty standard way of creating objects in C.

The question is, does the int exist if it is created in C, and returned to C++?

In other words, is the following guaranteed to be legal? Assume int is the same for C and C++.

foo.h

#ifdef __cplusplus
extern "C" {
#endif

int* foo(void);

#ifdef __cplusplus
}
#endif

foo.c

#include "foo.h"
#include <stdlib.h>

int* foo(void) {
    return malloc(sizeof(int));
}

main.cpp

#include "foo.h"
#include<cstdlib>

int main() {
    int* p = foo();
    *p = 42;
    std::free(p);
}

Links to discussions on mandatory nature of placement new:

  • Is placement new legally required for putting an int into a char array?
  • https://stackoverflow.com/a/46841038/4832499
  • https://groups.google.com/a/isocpp.org/forum/#!msg/std-discussion/rt2ivJnc4hg/Lr541AYgCQAJ
  • https://www.reddit.com/r/cpp/comments/5fk3wn/undefined_behavior_with_reinterpret_cast/dal28n0/
  • reinterpret_cast creating a trivially default-constructible object
like image 661
Passer By Avatar asked Oct 24 '17 11:10

Passer By


1 Answers

Yes! But only because int is a fundamental type. Its initialization is vacuous operation:

[dcl.init]/7:

To default-initialize an object of type T means:

  • If T is a (possibly cv-qualified) class type, constructors are considered. The applicable constructors are enumerated ([over.match.ctor]), and the best one for the initializer () is chosen through overload resolution. The constructor thus selected is called, with an empty argument list, to initialize the object.

  • If T is an array type, each element is default-initialized.

  • Otherwise, no initialization is performed.

Emphasis mine. Since "not initializing" an int is akin to default initialing it, it's lifetime begins once storage is allocated:

[basic.life]/1:

The lifetime of an object or reference is a runtime property of the object or reference. An object is said to have non-vacuous initialization if it is of a class or aggregate type and it or one of its subobjects is initialized by a constructor other than a trivial default constructor. The lifetime of an object of type T begins when:

  • storage with the proper alignment and size for type T is obtained, and
  • if the object has non-vacuous initialization, its initialization is complete,

Allocation of storage can be done in any way acceptable by the C++ standard. Yes, even just calling malloc. Compiling C code with a C++ compiler would be a very bad idea otherwise. And yet, the C++ FAQ has been suggesting it for years.


In addition, since the C++ standard defers to the C standard where malloc is concerned. I think that wording should be brought forth as well. And here it is:

7.22.3.4 The malloc function - Paragraph 2:

The malloc function allocates space for an object whose size is specified by size and whose value is indeterminate.

The "value is indeterminate" part kinda indicates there's an object there. Otherwise, how could it have any value, let alone an indeterminate one?

like image 188
StoryTeller - Unslander Monica Avatar answered Oct 19 '22 15:10

StoryTeller - Unslander Monica