On Thu, Aug 22, 2013 at 6:16 PM, Mike Stump <[email protected]> wrote:
> On Aug 22, 2013, at 2:28 PM, Gabriel Dos Reis <[email protected]>
> wrote:
>> On Thu, Aug 22, 2013 at 4:14 PM, Mike Stump <[email protected]> wrote:
>>> On Aug 22, 2013, at 9:45 AM, Gabriel Dos Reis
>>> <[email protected]> wrote:
>>>>> I.e. can I have something like
>>>>>
>>>>> int a;
>>>>> test()
>>>>> {
>>>>> int *b=new (int);
>>>>> }
>>>>>
>>>>> with custom implementation of new that returns &a?
>>>>
>>>> If the user-supplied operator new returns &a, then it must
>>>> also ensure that 'a' is not used anywhere else -- e.g. I you can't
>>>> do lvalue-to-value conversion on 'a' to see what is written there.
>>>
>>> This is wrong, in the c++97 standard there is no such limitation or
>>> restriction.
>>
>> Please, elaborate.
>
> Sure, there is no wording that limits as you describe. There is a limit for
> polymorphic classes and classes with virtual bases (See [class.cdtor], but
> that is due to the vtable pointer lifetime and vbase pointer (offset)
> lifetime. Essentially, you can't use viable pointers or do vbase conversions
> before they are set, and they are only set at a particular time. The
> standard keeps it simple and expands to non-POD, but I'd argue that from a
> QOI we should not make things that can work, not work. See below on QOI
> issues.
I think we must distinguish what is "wrong" according to the standards
we are implementing from what is "wrong" from a QoI point of view.
My reasoning (for C++98, but the same is true for C++11) is based
on 3.8/1:
[…]
The lifetime of an object of type T ends when:
-- if T is a class type with a non-trivial destructor (12.4),
the destructor call starts, or
-- the storage which the object occupies is reused or released.
Doing a placement-new on the storage occupied by 'a' is reusing
its storage, therefore ending its lifetime.
-- Gaby
>
> I can't quote it, since the limitation doesn't exist. I can quote the
> language that allows & on an object, that you can then cast this to be of a
> different type, and then dereference and use that type, if you want. I can
> quote the object lifetime rules, that describe when it comes into existence,
> and when it goes away. But, none of these are terribly surprising. If you
> want to narrow done what part of the language you're interested in, I can
> quote just that part.
>
> int a;
>
> a exists before the program runs, and exists till after the program is
> finished running (See [basic.stc.static]). That's the lifetime of it.
> During it's lifetime, you can use it in the ways the standard lets you. For
> example, ++a;. In the below:
>
> void foo() {
> char *cp = &a;
>
> [ … ]
> }
>
> cp's lifetime is from the declaration of it, til the }. The character object
> that cp points to has a lifetime. It's lifetime is from before the program
> runs, til after the program finishes. (See [basic.life]) It can be used any
> way that a lvalue character can be used. Since you can't use cp before it's
> lifetime, to use this character object outside of the lifetime of cp, you'd
> need another reference to it beyond just cp. Again, this isn't suppose to be
> surprising.
>
> Now, we do have wording like:
>
> 15If a program attempts to access the stored value of an object through
> an lvalue of other than one of the following types the behavior is
> undefined48):
>
> and we do have latitude to do things that uses that as a basis, but, once one
> ensures locking, say with atomics or volatile, to ensure the variable hits
> memory, I will argue that we can't make as much use of that from a quality of
> implementation viewpoint, despite the standard wording. Now, even without
> volatile and locking, from a quality of implementation point of view, we
> don't actually want to make full use of undefined. QOI still forces us to do
> the right thing. undefined means, we get to kill the user. QOI means, even
> though we can, we refrain from it, cause if we did, they would not like us.
>
> For the case of a int, and a placement new on that int, of an int. The
> behavior is mandated by the standard to work. For a allocation function,
> they are free to play games with persistence (or unexec a la emacs), with
> allocated objects and this too has to work. This means they can alias, and
> the standard says they can write this code and the standard mandates that it
> works.
>
> Now, the user can use:
>
> @item malloc
> @cindex @code{malloc} attribute
> The @code{malloc} attribute is used to tell the compiler that a function
> may be treated as if any non-@code{NULL} pointer it returns cannot
> alias any other pointer valid when the function returns and that the memory
> has undefined content.
> This often improves optimization.
> Standard functions with this property include @code{malloc} and
> @code{calloc}. @code{realloc}-like functions do not have this
> property as the memory pointed to does not have undefined content.
>
> on their allocation functions, if they want. And if they do, than what it
> says is true, by definition, but not by standard. When this isn't true, the
> user will refrain from using this attribute.