What is the exact meaning of the phrase "as if" in the standard and how does it work when a user can modify individual parts of the behavior.
The question is in regards to the C++ standard when talking about the nothrow version of operator new
. 18.4.1.1/7 reads (my emphasis):
This nothrow version of operator new returns a pointer obtained as if acquired from the ordinary version.
My understanding is that "as if" does not require a specific implementation as long as the behavior is appropriate. So if operator new
was implemented like this (I know this is not a compliant implementation as there is no loop or use of the new_handler; but I'm shortening that to focus on my issue):
// NOTE - not fully compliant - for illustration purposes only.
void *operator new(std::size_t s)
{
void *p = malloc(s);
if (p == 0)
throw std::bad_alloc();
return p;
}
Then it would be legal to write the nothrow version like this:
// NOTE - not fully compliant - for illustration purposes only.
void *operator new(std::size_t s, const std::nothrow_t &nt)
{
return malloc(s);
}
But let's say a program replaces operator new
to use some other allocator. Does "as if" mean the compiler has to automatically change the behavior of the nothrow version to use this other allocator? Is the developer required to replace both the plain and nothrow versions?
If the change in allocator in
operator new
makes an observable difference in the behaviour of a compliant C++ program then yes, it might require a change in the implementation of the no-throw version. Specifically ifoperator delete
expects only blocks allocated by the new allocator then the no-throw new must change.My reading is that the use of as if allows an implementation such as yours when the user hasn't overriden the standard
operator new
. As soon as he has, the implementation must not use amalloc
based no-throwoperator new
and must either call the user declared version explicitly or at least re-use enough of the user declared version that a conforming program cannot tell that this isn't how the no-throw version has been implemented.The developer should replace both the plain and nothrow versions. Check out this article on GOTW.
My assumption is that the standard puts requirements on compiler (and runtime) default implementations. So the "as if" you quote is meant to inform the compiler vendor that its default implementations of those methods must meet the specified criteria. If a developer chooses to override only one version of operator new, I do not think it is the compiler's responsibility to make all other versions of operator new compliant. It is the developer's responsibility. But that's all my opinion, I don't have the spec handy at the moment to see what it says in the front matter.
From 1.9 "Program execution:
and in an informational footnote:
The standard does specifically note that the "as-if" requirement is binding on a replacement version of the nothrow version of
operator new()
. However, as I read it, that requirement would fall to the programmer overridingoperator new()
not the compiler. The flip side of this responsibility is that I think the standard pretty much requires the default implementation of the nothrowoperator new()
provided by the library must do something along the lines of calling the throwingnew
in a try/catch and return 0 ifstd::bad_alloc
is caught.Where the "as if rule" could come in to play here is if the compiler/linker/whatever were smart enough to figure out that when the default throwing
new()
was in being used, the default non-throwingnew()
could take the shortcut, but if the default throwingnew()
was overridden, the default non-throwingnew()
would have to act differently. I'm sure this is technically possible for an implementation (even if you probably can't express it in standard C++). I'd be surprised if there was ever an implementation that did this.I might be reading too much into the requirement, but I think that's what can be inferred.