- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
默认放置 new
运算符在 18.6 [support.dynamic] ¶1 中声明,具有不抛出异常规范:
void* operator new (std::size_t size, void* ptr) noexcept;
这个函数除了 return ptr;
什么都不做,所以它是 noexcept
是合理的,但是根据 5.3.4 [expr.new] ¶15 这意味着编译器必须在调用对象的构造函数之前检查它是否返回 null:
-15-
[Note: unless an allocation function is declared with a non-throwing exception-specification (15.4), it indicates failure to allocate storage by throwing astd::bad_alloc
exception (Clause 15, 18.6.2.1); it returns a non-null pointer otherwise. If the allocation function is declared with a non-throwing exception-specification, it returns null to indicate failure to allocate storage and a non-null pointer otherwise. —end note] If the allocation function returns null, initialization shall not be done, the deallocation function shall not be called, and the value of the new-expression shall be null.
在我看来(特别是对于放置 new
,不是一般情况下)这种 null 检查是一个不幸的性能损失,尽管很小。
我一直在调试一些代码,其中在对性能非常敏感的代码路径中使用放置 new
以改进编译器的代码生成,并且在程序集中观察到 null 检查。通过提供特定于类的放置 new
重载,该重载使用抛出异常规范(即使它不可能抛出)声明,条件分支被删除,这也允许编译器生成更小的代码对于周围的内联函数。说放置new
函数可以抛出,即使它不能抛出的结果是明显更好的代码。
所以我一直想知道放置 new
情况是否真的需要空检查。它可以返回 null 的唯一方法是如果你将它传递给 null。虽然写是可能的,而且显然是合法的:
void* ptr = nullptr;
Obj* obj = new (ptr) Obj();
assert( obj == nullptr );
我不明白为什么会有用,我建议程序员在使用放置 new
之前必须明确检查 null 会更好,例如
Obj* obj = ptr ? new (ptr) Obj() : nullptr;
有没有人需要放置 new
来正确处理空指针的情况? (即没有添加明确的检查 ptr
是一个有效的内存位置。)
我想知道禁止将空指针传递给默认放置 new
函数是否合理,如果不是,是否有更好的方法来避免不必要的分支,而不是尝试告诉编译器该值不为空,例如
void* ptr = getAddress();
(void) *(Obj*)ptr; // inform the optimiser that dereferencing pointer is valid
Obj* obj = new (ptr) Obj();
或者:
void* ptr = getAddress();
if (!ptr)
__builtin_unreachable(); // same, but not portable
Obj* obj = new (ptr) Obj();
注意这个问题被有意标记为微优化,我不建议您为所有类型重载放置 new
以“提高”性能。这种影响在一个非常具体的性能关键案例中被注意到,并且基于分析和测量。
更新: DR 1748使用带有新位置的空指针使其行为未定义,因此不再需要编译器进行检查。
最佳答案
除了“有没有人需要放置 new 来正确处理空指针情况?”之外,我看不到很多问题。 (我没有),我认为这个案子很有趣,足以让人们对这个问题产生一些想法。
我认为标准被破坏或不完整 wrt 放置新功能和一般分配功能的要求。
如果您仔细查看引用的 §5.3.4,13,这意味着必须检查 每个 分配函数是否有返回的空指针,即使它不是 noexcept
。所以应该改写成
If the allocation function is declared with a non-throwing exception-specification and returns null, initialization shall not be done, the deallocation function shall not be called, and the value of the new-expression shall be null.
这不会损害分配函数抛出异常的有效性,因为它们必须遵守§3.7.4.1:
[...] If it is successful, it shall return the address of the start of a block of storage whose length in bytes shall be at least as large as the requested size. [...] The pointer returned shall be suitably aligned so that it can be converted to a pointer of any complete object type with a fundamental alignment requirement (3.11) and then used to access the object or array in the storage allocated (until the storage is explicitly deallocated by a call to a corresponding deallocation function).
以及§5.3.4,14:
[ Note: when the allocation function returns a value other than null, it must be a pointer to a block of storage in which space for the object has been reserved. The block of storage is assumed to be appropriately aligned and of the requested size. [...] -end note ]
显然,仅返回给定指针的放置 new 无法合理地检查可用存储大小和对齐方式。因此,
§18.6.1.3,1关于安置新说
[...] The provisions of (3.7.4) do not apply to these reserved placement forms of operator new and operator delete.
(我猜他们在那个地方没有提到§5.3.4,14。)
然而,这些段落间接说“如果你将垃圾指针传递给 palcement 函数,你会得到 UB,因为违反了 §5.3.4,14”。因此,由您来检查放置新位置的任何 poitner 的健全性。
本着这种精神,并通过重写 §5.3.4,13,标准可以从放置 new 中删除 noexcept
,从而导致对间接结论的补充:“......如果你传递null,你也会得到UB”。另一方面,与空指针相比,指针未对齐或指向内存太少的可能性要小得多。
但是,这将消除检查 null 的需要,并且非常符合“不要为不需要的东西付费”的理念。分配函数本身不需要检查,因为 §18.6.1.3,1 明确说明了这一点。
为了总结,可以考虑添加第二个重载
void* operator new(std::size_t size, void* ptr, const std::nothrow_t&) noexcept;
遗憾的是,向委员会提出此建议不太可能导致更改,因为它会破坏现有代码,依赖于放置 new 可以使用空指针。
关于c++ - 将空指针传递给新位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17571103/
我已经为使用 JGroups 编写了简单的测试。有两个像这样的简单应用程序 import org.jgroups.*; import org.jgroups.conf.ConfiguratorFact
我有一个通过 ajax 检索的 json 编码数据集。我尝试检索的一些数据点将返回 null 或空。 但是,我不希望将那些 null 或空值显示给最终用户,或传递给其他函数。 我现在正在做的是检查
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Why does one often see “null != variable” instead of “
嗨在我们公司,他们遵循与空值进行比较的严格规则。当我编码 if(variable!=null) 在代码审查中,我收到了对此的评论,将其更改为 if(null!=variable)。上面的代码对性能有影
我正在尝试使用 native Cordova QR 扫描仪插件编译项目,但是我不断收到此错误。据我了解,这是代码编写方式的问题,它向构造函数发送了错误的值,或者根本就没有找到构造函数。那么我该如何解决
我在装有 Java 1.8 的 Windows 10 上使用 Apache Nutch 1.14。我已按照 https://wiki.apache.org/nutch/NutchTutorial 中提
这个问题已经有答案了: 已关闭11 年前。 Possible Duplicate: what is “=null” and “ IS NULL” Is there any difference bet
Three-EyedRaven 内网渗透初期,我们都希望可以豪无遗漏的尽最大可能打开目标内网攻击面,故,设计该工具的初衷是解决某些工具内网探测速率慢、运行卡死、服务爆破误报率高以及socks流
我想在Scala中像在Java中那样做: public void recv(String from) { recv(from, null); } public void recv(String
我正在尝试从一组图像补丁中创建一个密码本。我已将图像(Caltech 101)分成20 X 20图像块。我想为每个补丁创建一个SIFT描述符。但是对于某些图像补丁,它不返回任何描述符/关键点。我尝试使
我在验证器类中自动连接的两个服务有问题。这些服务工作正常,因为在我的 Controller 中是自动连接的。我有一个 applicationContext.xml 文件和 MyApp-servlet.
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 已关闭10 年前。 问题必须表现出对要解决的问题的最低程度的了解。告诉我们您尝试过做什么,为什么不起作用,以
大家好,我正在对数据库进行正常的选择,但是 mysql_num_rowsis 为空,我不知道为什么,我有 7 行选择。 如果您发现问题,请告诉我。 真的谢谢。 代码如下: function get_b
我想以以下格式创建一个字符串:id[]=%@&stringdata[]=%@&id[]=%@&stringdata[]=%@&id[]=%@&stringdata[]=%@&等,在for循环中,我得到
我正在尝试使用以下代码将URL转换为字符串: NSURL *urlOfOpenedFile = _service.myURLRequest.URL; NSString *fileThatWasOpen
我正在尝试将NSNumber传递到正在工作的UInt32中。然后,我试图将UInt32填充到NSData对象中。但是,这在这里变得有些时髦... 当我尝试将NSData对象中的内容写成它返回的字符串(
我正在进行身份验证并收到空 cookie。我想存储这个 cookie,但服务器没有返回给我 cookie。但响应代码是 200 ok。 httpConn.setRequestProperty(
我认为 Button bTutorial1 = (Button) findViewById(R.layout.tutorial1); bTutorial1.setOnClickListener
我的 Controller 中有这样的东西: model.attribute("hiringManagerMap",hiringManagerMap); 我正在访问此 hiringManagerMap
我想知道如何以正确的方式清空列表。在 div 中有一个列表然后清空 div 或列表更好吗? 我知道这是一个蹩脚的问题,但请帮助我理解这个 empty() 函数:) 案例)如果我运行这个脚本会发生什么:
我是一名优秀的程序员,十分优秀!