13

标准中短语“好像”的确切含义是什么,以及当用户可以修改行为的各个部分时它是如何工作的。

在谈论operator new. 18.4.1.1/7 读到(我的重点):

这个 nothrow 版本的 operator new 返回一个指针,就像从普通版本中获取一样。

我的理解是,只要行为合适,“好像”就不需要特定的实现。所以 ifoperator new是这样实现的(我知道这不是一个兼容的实现,因为没有循环或使用 new_handler;但我正在缩短它以专注于我的问题):

// 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;
}

然后像这样编写 nothrow 版本是合法的:

// NOTE - not fully compliant - for illustration purposes only.
void *operator new(std::size_t s, const std::nothrow_t &nt)
{
    return malloc(s);
}

但是假设一个程序替换operator new为使用其他分配器。“好像”是否意味着编译器必须自动更改 nothrow 版本的行为才能使用其他分配器?开发人员是否需要同时替换普通版本和 nothrow 版本?

4

3 回答 3

7

从1.9“程序执行:

需要符合要求的实现来模拟(仅)抽象机器的可观察行为

并在信息脚注中:

这个规定有时被称为“好像”规则,因为只要从可观察的行为中可以确定,只要结果是好像已经遵守了要求,实施就可以自由地忽略本国际标准的任何要求的程序。例如,如果一个实际的实现可以推断出它的值没有被使用并且没有产生影响程序可观察行为的副作用,那么它就不需要评估表达式的一部分。

该标准确实特别指出,“as-if”要求对 .nothrow 版本的替换版本具有约束力operator new()。但是,当我读到它时,该要求将落在程序员operator new()而不是编译器之上。这个责任的另一面是,我认为标准几乎要求库提供的 nothrow 的默认实现必须按照在 try/catchoperator new()中调用 throwing 的方式做一些事情,如果被捕获则返回 0。newstd::bad_alloc

“好像规则”可以在这里发挥作用的地方是,如果编译器/链接器/任何东西足够聪明,可以弄清楚在使用默认抛出new()时,默认不抛出new()可以走捷径,但如果默认投掷new()被覆盖,默认的非投掷new()必须采取不同的行动。我确信这在技术上是可行的(即使您可能无法用标准 C++ 表达它)。如果曾经有一个实现可以做到这一点,我会感到惊讶。

我可能对要求读得太多了,但我认为这是可以推断的。

于 2010-02-21T18:57:48.547 回答
2

如果分配器中的更改operator new对兼容的 C++ 程序的行为产生了可观察到的差异,那么是的,它可能需要更改no-throw版本的实现。具体来说,如果operator delete只期望新分配器分配的块,那么不抛出新的必须更改。

我的阅读是,当用户没有覆盖标准时,使用as ifoperator new允许像您这样的实现。只要他有,实现就不能使用malloc基于的无抛出 operator new,并且必须显式调用用户声明的版本,或者至少重用足够多的用户声明的版本,以致符合程序无法判断这不是已实施无抛版本。

于 2010-02-21T17:11:06.867 回答
0

开发人员应该同时替换 plain 和 nothrow 版本。看看这篇关于 GOTW 的文章。

我的假设是该标准对编译器(和运行时)默认实现提出了要求。因此,您引用的“好像”是为了通知编译器供应商,这些方法的默认实现必须满足指定的标准。如果开发人员选择仅覆盖 operator new 的一个版本,我认为编译器没有责任使所有其他版本的 operator new 兼容。这是开发商的责任。但这就是我的全部观点,我目前没有手边的规范来查看它在前面的内容。

于 2010-02-21T17:22:00.993 回答