[英]Is implicit conversion from unique_ptr to raw pointer supported?
I was reading Effective C++ 3rd Edition. 我正在阅读有效的C ++第三版。 In page 70, the author says:
在第70页中,作者说:
Like virtually all smart pointer classes,
tr1::shared_ptr
andauto_ptr
also overload the pointer dereferencing operators (operator->
andoperator*
), and this allows implicit conversion to the underlying raw pointers (...)与几乎所有智能指针类一样,
tr1::shared_ptr
和auto_ptr
也会使指针解引用运算符(operator->
和operator*
)过载,这允许隐式转换为基础原始指针(...)
He then shows an example with shared_ptr
(which was part of tr1
at the time) featuring implicit conversion based on a class named Investment
: 然后,他展示了
shared_ptr
(当时是tr1
一部分)的示例,该示例基于名为Investment
的类进行隐式转换:
shared_ptr<Investment> pi1();
bool taxable1 = !(pi1->isTaxFree());
^implicit conversion
shared_ptr<Investment> pi2();
bool taxable2 = !((*pi2).isTaxFree());
^implicit conversion
Well, I have since then written a few test cases with unique_ptr
and they hold up. 好吧,从那时起,我就用
unique_ptr
编写了一些测试用例,它们得到了unique_ptr
。
I also found out about unique_ptr
supporting arrays and shared_ptr
also going to (see note). 我还发现了支持数组的
unique_ptr
和shared_ptr
也将要使用 (请参阅注释)。 However, in my testing, implicit conversion does not seem to work for smart pointers around arrays. 但是,在我的测试中,隐式转换似乎不适用于数组周围的智能指针。
Example: I wanted this to be valid... 示例:我希望这是有效的...
unique_ptr<int[]> test(new int[1]);
(*test)[0] = 5;
but it is not, according to my compiler (Visual C++ 2015 Update 3). 但根据我的编译器(Visual C ++ 2015 Update 3),它不是。
Then, from a little research, I found some evidence suggesting that implicit conversion isn't supported at all... like this one for instance: https://herbsutter.com/2012/06/21/reader-qa-why-dont-modern-smart-pointers-implicitly-convert-to . 然后,通过一项小小的研究,我发现了一些证据表明根本不支持隐式转换...例如: https : //herbsutter.com/2012/06/21/reader-qa-why-不要将现代智能指针隐式转换为 。
At this point I am in doubt. 在这一点上,我有疑问。 Is it supported (by the Standard) , or is it not?
(受标准支持 ) 还是不支持?
Note: The book might be a bit outdated on this topic, since the author also says on page 65 that "there is nothing like auto_ptr
or tr1::shared_ptr
for dinamically allocated arrays, not even in TR1". 注意:这本书在这个主题上可能有点过时,因为作者在第65页上还说过:“对于动态分配的数组,没有什么像
auto_ptr
或tr1::shared_ptr
一样,甚至在TR1中也没有。”
Well, here's the thing. 好吧,这就是事情。 There is no implicit conversion to the underlying pointer, you have to call a specific
get
member function (it's a theme in the standard library, think std::string::c_str
). 没有对基础指针的隐式转换,您必须调用特定的
get
成员函数(这是标准库中的主题,请考虑std::string::c_str
)。
But that's a good thing! 但这是一件好事! Implicitly converting the pointer can break the guarantees of
unique_ptr
. 隐式转换指针可能会破坏
unique_ptr
的保证。 Consider the following: 考虑以下:
std::unique_ptr<int> p1(new int);
std::unique_ptr<int> p2(p1);
In the above code, the compiler can try to pass p1
s pointee to p2
! 在上面的代码中,编译器可以尝试将
p1
的pointee传递给p2
! (It won't since this call will be ambiguous anyway, but assume it wasn't). (因为此调用无论如何都不会模棱两可,但是假设不是)。 They will both call
delete
on it! 他们都将要求
delete
它!
But we still want to use the smart pointer as if it was a raw one. 但是我们仍然希望使用智能指针,就像它是原始指针一样。 Hence all the operators are overloaded.
因此,所有操作员都超负荷了。
Now let's consider your code: 现在,让我们考虑一下您的代码:
(*test)[0] = 5;
It calls unique_ptr::operator*
which produces an int&
1 . 它调用
unique_ptr::operator*
,它生成一个int&
1 。 Then you try use the subscript operator on it. 然后尝试在其上使用下标运算符。 That's your error.
那是你的错误
If you have a std::unique_ptr<int[]>
than just use the operator[]
overload that the handle provides: 如果您拥有
std::unique_ptr<int[]>
而不仅仅是使用该句柄提供的operator[]
重载:
test[0] = 5;
1 As David Scarlett pointed out, it shouldn't even compile. 1正如David Scarlett指出的那样,它甚至不应该编译。 The array version isn't supposed to have this operator.
数组版本不应该具有此运算符。
As StoryTeller indicates, implicit conversions would ruin the show, but I'd like to suggest another way of thinking about this: 正如StoryTeller所指出的那样,隐式转换会破坏演出,但我想提出另一种思考方式:
Smart pointers like unique_ptr
and shared_ptr
try to hide the underlying raw pointer because they try to maintain a certain kind of ownership semantics over it. 像
unique_ptr
和shared_ptr
这样的智能指针试图隐藏底层的原始指针,因为它们试图在其上保留某种所有权语义。 If you were to freely obtain that pointer and pass it around, you could easily violate those semantics. 如果要自由获取该指针并将其传递,则很容易违反这些语义。 They still provide a way to access it (
get
), since they couldn't stop you completely even if they wanted to (after all you can just follow the smart pointer and get the address of the pointee). 他们仍然提供了一种访问它的方法(
get
),因为即使他们愿意也无法完全阻止您(毕竟,您可以跟随智能指针并获取指针的地址)。 But they still want to put a barrier to make sure you don't access it accidentally. 但是他们仍然想设置障碍,以确保您不会意外访问它。
All is not lost though! 一切都不会丢失! You can still gain that syntactic convenience by defining a new kind of smart pointer with very weak semantics, such that it can safely be implicitly constructed from most other smart pointers.
您仍然可以通过定义一种语义非常弱的新型智能指针来获得这种语法上的便利,以便可以从大多数其他智能指针中隐式地构造该智能指针。 Consider:
考虑:
// ipiwdostbtetci_ptr stands for :
// I promise I wont delete or store this beyond the expression that created it ptr
template<class T>
struct ipiwdostbtetci_ptr {
T * _ptr;
T & operator*() {return *_ptr;}
T * operator->(){return _ptr;}
ipiwdostbtetci_ptr(T * raw): _ptr{raw} {}
ipiwdostbtetci_ptr(const std::unique_ptr<T> & unq): _ptr{unq.get()} {}
ipiwdostbtetci_ptr(const std::shared_ptr<T> & shr): _ptr{shr.get()} {}
};
So, what's the point of this satirically named smart pointer? 那么,这个讽刺命名的智能指针有什么意义呢? It's just a kind of pointer that's verbally given a contract that the user will never keep it or a copy of it alive beyond the expression that created it and the user will also never attempt to delete it.
这只是一种指针,它在口头上赋予了用户永远不会保留它或它的副本超出创建它的表达式的生命,并且用户也永远不会尝试删除它的指针。 With these constraints followed by the user (without the compiler checking it), it's completely safe to implicitly convert many smart pointers as well as any raw pointer.
在用户遵循这些约束的情况下(无需编译器对其进行检查),隐式转换许多智能指针以及任何原始指针都是完全安全的。
Now you can implement functions that expect a ipiwdostbtetci_ptr
(with the assumption that they'll honor the semantics), and conveniently call them: 现在,您可以实现期望具有
ipiwdostbtetci_ptr
函数(假设它们将ipiwdostbtetci_ptr
语义),并方便地调用它们:
void f(ipiwdostbtetci_ptr<MyClass>);
...
std::unique_ptr<MyClass> p = ...
f(p);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.