5

[basic.indet] p1 says:

When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced.

What exactly does it mean for storage to be acquired for an object? Consider this code snippet:

int a = 0;
new (&a) int;

When is the storage for the int object created by the new-expression acquired? Is it when the storage for the original object that was created by definition was acquired, or would it be acquired when the object is created by the new-expression?

(Side note: According to P0593 this new object will have an indeterminate value due to [basic.life] p4, however, this is not explicitly specified, unless storage is considered to be acquired when the second object is created)

Edit: This seems to be the subject of a unanswered defect report CWG 1997

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Krystian S
  • 1,586
  • 7
  • 23

2 Answers2

1

The storage is initially allocated for the automatic object. The placement-new then reuses that storage for the dynamic object.

The standard doesn't appear to define the meaning of the word "obtain" in relation to allocation and reusage. If it was restricted to mean the same as "allocate", then it would be a redundant term, so it is reasonable to asssume that it covers both allocation, and reusage.

Under this interpretation, the storage would have been obtained at the placement new expression. And indeed, the value would be indeterminate. There is a trick to keep the value:

int a = 0;
int orig = a;
new (&a) int(orig);

A decent optimising compiler can see that the copies are redundant. For arrays, same can be achieved with memcpy, and those can be optimised away too as long as the length is constant.

eerorika
  • 232,697
  • 12
  • 197
  • 326
1

Actually, it's quite simple. From [expr.new]/8:

A new-expression may obtain storage for the object by calling an allocation function

Placement-new is an allocation function. It may only return the same pointer it was given, but this process is still considered "obtaining storage for the object". That storage being the storage pointed to by &a. And therefore, it works exactly as expected. The storage currently in use by a is being reused. So the current a ends its lifetime, and a new int begins its lifetime in the same storage.

"Obtain storage for an object" doesn't mean "make storage appear that wasn't there before". It means exactly what it says: to get a piece of storage for the purpose of putting an object there. This is different from simply getting a piece of storage. That the piece of storage may already be in use by some other object is orthogonal.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • How does it differ from "simply getting a piece of storage"? – Krystian S Oct 12 '19 at 17:39
  • @KrystianS: I don't understand what you mean. You asked how that construct obtains storage for an object. It happens by calling an allocation function. What happens with that function is essentially irrelevant; the storage it returns is considered "obtained for the object" by virtue of being the result of a thing that says "this construct obtains storage for the object by doing X". – Nicol Bolas Oct 12 '19 at 18:53
  • Hm, perhaps its just a grammatical error in your response, what I'm referring to is " It means exactly what it says: to get a piece of storage for the purpose of putting an object there. *This is different from simply getting a piece of storage*" I'm assuming by "get" you mean allocate. – Krystian S Oct 12 '19 at 20:39
  • @KrystianS: No, I mean "get". The term "allocate" suggests that the storage wasn't available or wasn't in use beforehand. That's why the standard uses the word "obtain" rather than "allocate," since the latter has connotations that aren't necessarily the case. – Nicol Bolas Oct 12 '19 at 20:54
  • So how does "to get a piece of storage for the purpose of putting an object there" differ from "This is different from simply getting a piece of storage." – Krystian S Oct 12 '19 at 21:21
  • 1
    Since *get* is synonymous with *obtain*, using it to define the latter doesn't really help. Worse, one of the meanings of *get* in a programming context is very specifically to fetch an object or reference to an object that already exists. – Caleb Oct 14 '19 at 13:04
  • @Caleb: "*Since get is synonymous with obtain, using it to define the latter doesn't really help.*" It's a simple, English word. It means exactly what the dictionary says it means. The standard is not trying to trick you; it is not creating a special meaning for "obtain". That's my point. – Nicol Bolas Oct 14 '19 at 13:24
  • @NicolBolas It might help if you could expand on how *get a piece of storage for the purpose of putting an object there* is *different from getting a piece of storage*. I'm a native speaker of English and an experienced programmer, but what you're trying to say is still pretty opaque to me. – Caleb Oct 14 '19 at 13:47
  • @Caleb: Just replace the key words with symbols. How is "X a Y for the purpose of Z" different from "X a Y"? Because in the former case, you're doing it for the purpose of Z. That's how it's different. It's a subset of cases where you "X a Y". – Nicol Bolas Oct 14 '19 at 14:53
  • @NicolBolas I see what you're saying, but I think saying that it's *different* is confusing. Wouldn't you agree that getting the storage is exactly the same in both cases, and the only difference is what you then do with the storage once you've got it? I hate to get into a semantic argument about it, but the question is *about* semantics, so... – Caleb Oct 14 '19 at 15:12
  • @Caleb: It's different because, as far as the standard is concerned, the idea of "obtaining storage" *outside* of the purpose of "for the object" is not relevant. The standard only gives meaning to "obtain storage" in the specific context of making an object. That is, directly calling an allocation function could be described as "obtaining storage", but that has no special meaning in C++. You just get a `void*` or whatever. "Obtaining storage" only has special meaning when it happens as part of creating an object. – Nicol Bolas Oct 14 '19 at 15:26