我正在阅读Effective C ++ 3rd Edition。在第70页,作者说:
与几乎所有智能指针类一样,
tr1::shared_ptr
和auto_ptr
也会重载指针解引用运算符(operator->
和operator*
),这允许隐式转换为基础原始类指针(...)
然后,他展示了shared_ptr
(当时是tr1
的一部分)的示例,其中包含基于名为Investment
的类的隐式转换:
shared_ptr<Investment> pi1();
bool taxable1 = !(pi1->isTaxFree());
^implicit conversion
shared_ptr<Investment> pi2();
bool taxable2 = !((*pi2).isTaxFree());
^implicit conversion
好吧,从那时起我就用unique_ptr
编写了一些测试用例并且他们坚持了下来。
我还发现了unique_ptr
supporting arrays和shared_ptr
also going to(参见注释)。但是,在我的测试中,隐式转换似乎不适用于数组周围的智能指针。
示例:我希望这个有效...
unique_ptr<int[]> test(new int[1]);
(*test)[0] = 5;
但根据我的编译器(Visual C ++ 2015 Update 3),它不是。
然后,从一个小小的研究中,我发现了一些证据表明隐含的转换根本不受支持......例如:https://herbsutter.com/2012/06/21/reader-qa-why-dont-modern-smart-pointers-implicitly-convert-to。
此时我有点怀疑。 支持(标准版),还是不支持?
注意:这本书的主题可能有点过时了,因为作者在第65页也说过,对于dinamically分配的数组,没有像auto_ptr
或tr1::shared_ptr
这样的内容,甚至在TR1& #34;
答案 0 :(得分:4)
嗯,这就是事情。没有隐式转换到底层指针,你必须调用一个特定的get
成员函数(它是标准库中的主题,想想std::string::c_str
)。
但那是件好事!隐式转换指针可能会破坏unique_ptr
的保证。请考虑以下事项:
std::unique_ptr<int> p1(new int);
std::unique_ptr<int> p2(p1);
在上面的代码中,编译器可以尝试将p1
的指针传递给p2
! (它不会因为这个调用无论如何都会模棱两可,但假设它不是)。他们都会打电话给delete
!
但我们仍然希望将智能指针用作原始指针。因此,所有运营商都过载了。
现在让我们考虑你的代码:
(*test)[0] = 5;
调用unique_ptr::operator*
生成int&
1 。然后尝试在其上使用下标运算符。那是你的错误
如果你有一个std::unique_ptr<int[]>
而不仅仅使用句柄提供的operator[]
重载:
test[0] = 5;
1 正如 David Scarlett 指出的那样,它甚至不应该编译。数组版本不应该有这个操作符。
答案 1 :(得分:1)
正如StoryTeller所说,隐含的转换会破坏节目,但我想提出另一种思考方式:
像unique_ptr
和shared_ptr
这样的智能指针尝试隐藏底层原始指针,因为它们试图在其上维护某种所有权语义。如果你要自由地获取指针并传递它,你很容易违反这些语义。他们仍然提供了一种访问它的方法(get
),因为即使他们想要它们也无法完全阻止你(毕竟你可以只关注智能指针并获取指针的地址)。但他们仍然希望设置一个障碍,以确保您不会意外访问它。
虽然一切都没有丢失!通过定义具有非常弱的语义的新类型的智能指针,您仍然可以获得语法上的便利,这样可以安全地从大多数其他智能指针隐式构造它。考虑:
// 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()} {}
};
那么,这个讽刺命名的智能指针是什么意思呢?它只是一种指针,口头上给出了一个合同,用户永远不会保留它或者它的副本超出创建它的表达式,用户也永远不会尝试删除它。由于用户遵循这些约束(没有编译器检查它),隐式转换许多智能指针以及任何原始指针都是完全安全的。
现在你可以实现期望ipiwdostbtetci_ptr
的函数(假设它们会尊重语义),并方便地调用它们:
void f(ipiwdostbtetci_ptr<MyClass>);
...
std::unique_ptr<MyClass> p = ...
f(p);