我在调试崩溃时偶然发现了一个与此类似的代码,因为它取消了引用的内存。
template<typename RaiiObject, typename HandleType>
const HandleType& ExtractHandle(const RaiiObject &value){
const HandleType* val = value.get(); // get underlying managed object
return static_cast<const HandleType&>(*val);
}
在调用者方面,代码如下所示:
const auto &x = ExtractHandle(GetAHandle());
这绝对是一个问题,因为我们将从ExtractHandle
获取的基础对象的引用将悬空,因为管理它的Raii对象将会过期。
现在修复此问题的开发人员通过引用取代了捕获按值捕获。
auto x = ExtractHandle(GetAHandle());
他的说法是,由于我们正在制作副本,因此我们是安全的,因为GetAHandle返回的x值不会消失,直到调用Handle的复制构造函数。这个假设是否正确?标准是否明确规定上述提议的修复不是UB?
注意:尽管这种设计的正确性和实用性肯定会受到质疑,但更重要的是,按值复制是否能保证定义良好的行为
答案 0 :(得分:2)
这很好。
由$python
Python 2.7.6 (default, Jun 22 2015, 18:00:18)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests;requests.__version__
'2.9.1'
>>> url = 'https://close5.com/home/'
>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup(requests.get(url).content, "html5lib")
/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util/ssl_.py:315: SNIMissingWarning: An HTTPS request has been made, but the SNI (Subject Name Indication) extension to TLS is not available on this platform. This may cause the server to present an incorrect TLS certificate, which can cause validation failures. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#snimissingwarning.
SNIMissingWarning
/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util/ssl_.py:120: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
InsecurePlatformWarning
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 67, in get
return request('get', url, params=params, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 53, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 468, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 576, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 447, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: [Errno 1] _ssl.c:510: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
>>>
创建的临时文件只会在该语句的末尾被销毁,因此只要你的复制构造函数没有保留该对象内部的任何句柄,你就可以了。
GetAHandle()
[...]临时对象作为最后一步被销毁 在评估全表达式(1.9)时(词法上)包含创建它们的点。 [...]
答案 1 :(得分:2)
做得好。返回一份副本并完成它:
template<typename RaiiObject, typename HandleType>
HandleType ExtractHandle(const RaiiObject &value){
return *value.get(); // get underlying managed object
}
在这种情况下,其中任何一个都有效:
const auto &x = ExtractHandle(GetAHandle());
auto x = ExtractHandle(GetAHandle());
因为有一个特殊的规则可以在引用的生命周期内保持对const引用的临时活动绑定。