7

The C++ standard refers to the term "dynamic type" (and the C standard refers to "effective type" in the similar context), for example

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:

  • the dynamic type of the object,

But how is the dynamic type of the object allocated with malloc determined?

For example:

void *p = malloc(sizeof(int));
int *pi = (int*)p;

Will the dynamic type of the object pointed to by pi be int?

Community
  • 1
  • 1
vitaut
  • 49,672
  • 25
  • 199
  • 336
  • 2
    I think your assumption is wrong, in C that term doesn't seem to exist. Perhaps you mean "effective type"? Also I think the rules for these things are probably quite different for C an C++, so maybe you'd better ask two separate questions. – Jens Gustedt Mar 15 '16 at 20:26
  • In C++, dynamic type is an actual derived type pointed to by a pointer of a base type. Nothing to do with C. – ftynse Mar 15 '16 at 20:27
  • 1
    @JensGustedt You are right, it's called "effective type" in C. – vitaut Mar 15 '16 at 20:28
  • Do you mean dynamic casting? – Jiminion Mar 15 '16 at 20:28
  • http://stackoverflow.com/questions/13723839/strict-aliasing-rules-for-allocated-objects – Jiminion Mar 15 '16 at 20:29
  • I've updated the question. – vitaut Mar 15 '16 at 20:29
  • 2
    @vitaut: The terms "effective type" and "dynamic type" have *nothing at all* to do with one another. – Nicol Bolas Mar 15 '16 at 20:35
  • @NicolBolas they are used in exactly the same context (aliasing) in C and C++ standards. Anyway, I'm more interested in C++ interpretation. – vitaut Mar 15 '16 at 20:36
  • Reminds me of http://stackoverflow.com/q/15899369/560648 – Lightness Races in Orbit Mar 15 '16 at 20:47
  • @M.M: An object may be a region of storage, but that does not require that a region of storage is an object. Section 3.8 explains the lifetime rules for objects. It also explains what you can do with an object that has yet to begin its lifetime. – Nicol Bolas Mar 15 '16 at 20:53
  • 1
    @M.M: But there *is no* "object of type T" yet. Where are you getting `float` and `int` from? They aren't part of the `malloc` call. There is storage without an object. All objects require storage, but not all storage requires an object. – Nicol Bolas Mar 15 '16 at 21:07
  • @M.M: Again, `int` is not mentioned in `malloc(4)`. There is no "object of type T" yet; there is simply storage suitable for one. – Nicol Bolas Mar 15 '16 at 21:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/106399/discussion-between-nicol-bolas-and-m-m). – Nicol Bolas Mar 15 '16 at 21:44
  • @M.M: The answer to that question is irrelevant to the OP, who is *not* asking about lifetime issues. He's asking about the type of an object. – Nicol Bolas Mar 15 '16 at 21:52
  • @M.M: The standard language for dynamic types does not allow for the possibility of an object having multiple dynamic types. Your interpretation of the lifetime rules requires that an allocation of storage be an object which is *simultaneously* of every single type that could fit into that storage. Nothing in C++ allows an object to have multiple (unrelated) types, nor do the rules for dynamic types allow an object to have more than one. So clearly, your interpretation is in error. – Nicol Bolas Mar 15 '16 at 22:04
  • @M.M: I fail to see how "everyone's interpretation is in error", when the errors all go away once you stop believing that the lifetime section says that unallocated storage creates objects of every type that can fit into it. That's the contradictory part, and you are the only one reading that into it. – Nicol Bolas Mar 15 '16 at 22:09
  • @M.M `malloc` doesn't create an object. This is a well-known and zero disputed fact in the expert community (you should find quotes on this in both std-discussion and SG12 mailing lists). Where on earth did you get that from? – Columbo Mar 15 '16 at 23:15
  • Assuming that malloc returns untyped memory (which I think it does), at what point the dynamic type becomes "assigned" to it? Is it when we create the first pointer (pi) to the allocated memory or elsewhere? – vitaut Mar 15 '16 at 23:22
  • I've opened another question (http://stackoverflow.com/q/36024325/471164) to clarify the second part because this one turned out to be too focused on what dynamic type is. Thanks everyone for an interesting discussion. – vitaut Mar 15 '16 at 23:44
  • @M.M Yes, quite right. Dereferencing `p` is undefined. And [basic.life]/1 talks about objects; here, no objects are involved. We didn't allocate storage *for a particular object*. We just allocated storage. Arguing that this suddenly creates all possible objects is nonsense and totally destroys the potential of optimizations in this area. – Columbo Mar 16 '16 at 00:08
  • @M.M …so what have you proven now? [Here](http://stackoverflow.com/questions/36024325/at-what-point-does-memory-allocated-by-malloc-get-a-type#comment59700160_36024383)'s a similar question. It's UB unless `p` points to an object, which it clearly doesn't, for widely accepted reasons. – Columbo Mar 16 '16 at 00:20
  • @NicolBolas I've done a comment-cleanup on my old comments here, since they were wrong – M.M Feb 18 '17 at 01:00

5 Answers5

8

According to the C++ specification:

Dynamic type:

<glvalue> type of the most derived object (1.8) to which the glvalue denoted by a glvalue expression refers

The return value of malloc is a block of uninitialized storage. No object has been constructed within that storage. And therefore it has no dynamic type.

The void* does not point to an object, and only objects have a dynamic type.

You can create an object within that storage by beginning its lifetime. But until you do so, it's just storage.

Community
  • 1
  • 1
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
5

In C, the effective type is only relevant when you access an object. Then in is determined by

  • the declaration type, if it has one
  • the type of another object of which it is a copy (eg. memcpy)
  • the type of the lvalue through which it is accessed, e.g if a void* is converted to another pointer type (e.g int*), which then is dereferenced.

The latter is usually what happens with malloced objects, if you assign the return value of malloc to a pointer type.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • In C++, which is what this question is concerned about, `malloc` does not create objects. Simply aliasing the raw storage it yields via `int` is complete nonsense. – Columbo Mar 15 '16 at 23:12
  • 1
    @Columbo, the question was also tagged C when I answered it. – Jens Gustedt Mar 16 '16 at 14:04
3

Dynamic type is a formal term to describe essentially polymorphic objects i.e. ones with at least one virtual function. It is thus a C++ term as C has no concept of virtual, for example.

But how is the dynamic type of the object allocated with malloc determined?

It isn't. malloc allocates N raw bytes of memory and returns it through a void* - it's your job to infer the right type. Moreover, this memory just represents the area where the object is placed, but this object will not be alive till you explicitly call its constructor. (again, from a C++ perspective)

Will the dynamic type of the object pointed to by pi be int?

No, because the term dynamic type is meaningful when describing object with class types. int is not nor can be.

class Foo
{
   //virtual ~Foo() = default; 
   virtual void f() {}
};

class Bar : public Foo
{
  virtual void f() {}
};

// ...
Foo *ptr = new Bar();

Here Foo is the static type of ptr while Bar is its dynamic type.

edmz
  • 8,220
  • 2
  • 26
  • 45
  • 2
    I don't think this is right, because in the standard "dynamic type" seems to include primitive types. – vitaut Mar 15 '16 at 20:31
  • @vitaut: Only in the most technical sense does it include non-virtual types. A non-virtual type's dynamic type is itself. – Nicol Bolas Mar 15 '16 at 20:34
  • 1
    dynamic type type of the most derived object (1.8) to which the glvalue denoted by a glvalue expression refers [Example: if a pointer (8.3.1) p whose static type is “pointer to class B” is pointing to an object of class D, derived from B (Clause 10), the dynamic type of the expression *p is “D.” References (8.3.2) are treated similarly. — end example ] – ftynse Mar 15 '16 at 20:35
  • @vitaut If you mean _effective type_, then it's just `int`. – edmz Mar 15 '16 at 20:38
  • 1
    @vitaut: I understand the terms may appear to be correlated, but they quite aren't; if you have suggestions to make this clearer, please let me know. – edmz Mar 15 '16 at 20:40
  • 1
    The C++ standard doesn't use the term "effective type". – vitaut Mar 15 '16 at 20:41
3

The status quo is that malloc does not create objects. The only constructs that do are new expressions, definitions, casts and assignments to variant members. See P0137R0 for proper wording on this.

If you wanted to use the storage yielded by malloc, assuming that it is properly aligned (which is the case unless you use extended alignments), employ a call to placement new:

auto p = malloc(sizeof(int));
int* i = new (p) int{0};
// i points to an object of type int, initialized to zero

Hence using malloc in C++ is quite useless, as bog-standard new effectively combines the above steps into one.

See also @T.C.'s answer in the related question of the asker.

Community
  • 1
  • 1
Columbo
  • 60,038
  • 8
  • 155
  • 203
0

As per 1.3.7 in C++11 standard,

dynamic type glvalue type of the most derived object (1.8) to which the glvalue denoted by a glvalue expression refers [Example: if a pointer (8.3.1) p whose static type is “pointer to class B” is pointing to an object of class D, derived from B (Clause 10), the dynamic type of the expression *p is “D.” References (8.3.2) are treated similarly. — end example ]

for an example

class A {}
class B : public A {}
A *a = new B;

the "static" type of a is A * while its dynamic type is B *.

The idea of referencing not the same type comes to protect from something like

class A{}
class B : public A {int x;}
class C : public A {int y;}
A *a = new B;
reinterpret_cast<C *>(a)->x;

which may lead to undefined behavior.

void * does not point to an object, but the distinction between dynamic and declaration type makes sense only for objects.

ftynse
  • 787
  • 4
  • 9
  • Thanks for the standard quote, but what about the malloc result? Will object pointed to by pi have dynamic type int? – vitaut Mar 15 '16 at 20:39