是否支持从唯一指针到原始指针的隐式转换? 我正在阅读有效的C++第三版。在第70页,作者说:

是否支持从唯一指针到原始指针的隐式转换? 我正在阅读有效的C++第三版。在第70页,作者说:,c++,arrays,standards,smart-pointers,implicit-conversion,C++,Arrays,Standards,Smart Pointers,Implicit Conversion,与几乎所有智能指针类一样,tr1::shared_ptr和auto_ptr也重载指针解引用操作符(操作符->和操作符*),这允许隐式转换到底层原始指针(…) 然后,他展示了一个具有shared\u ptr(当时是tr1的一部分)的示例,该示例基于名为Investment的类进行隐式转换: shared_ptr<Investment> pi1(); bool taxable1 = !(pi1->isTaxFree()); ^implicit

与几乎所有智能指针类一样,
tr1::shared_ptr
auto_ptr
也重载指针解引用操作符(
操作符->
操作符*
),这允许隐式转换到底层原始指针(…)

然后,他展示了一个具有
shared\u ptr
(当时是
tr1
的一部分)的示例,该示例基于名为
Investment
的类进行隐式转换:

shared_ptr<Investment> pi1();
bool taxable1 = !(pi1->isTaxFree());
                    ^implicit conversion

shared_ptr<Investment> pi2();
bool taxable2 = !((*pi2).isTaxFree());
                    ^implicit conversion
<>但是,根据我的编译器(Visual C++ 2015更新3),它不是。 然后,通过一些研究,我发现一些证据表明隐式转换根本不受支持。。。比如这个例子:

在这一点上,我感到怀疑它是受标准支持的还是不受标准支持的?



注意:这本书在这个主题上可能有点过时,因为作者在第65页还说,“对于动态分配的数组,没有什么比
auto\u ptr
tr1::shared\u ptr
更适合,即使在tr1中也不适合。”。没有对底层指针的隐式转换,您必须调用特定的
get
成员函数(它是标准库中的一个主题,想想
std::string::c_str

但这是件好事!隐式转换指针可能会破坏
unique\u ptr
的保证。考虑以下事项:

std::unique_ptr<int> p1(new int);
std::unique_ptr<int> p2(p1);
它调用
unique\u ptr::operator*
,这将生成
int&
1。然后尝试对其使用下标运算符。那是你的错误。
如果您有一个
std::unique\u ptr
,则只需使用句柄提供的
操作符[]
重载即可:

test[0] = 5;


正如大卫·斯佳丽所指出的,它甚至不应该编译。数组版本不应该有这个操作符。

正如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()} {}
};

*测试[0]=5
您尊重
唯一的\u ptr::operator[]
的结果。当然,对于一个普通的
int
@StoryTeller来说,这是不够公平的。我想,我已经解决了这个问题……FWIW,Scott Meyers(高效的现代C++)说:“对于数组,std::unique_ptr的存在应该是您唯一感兴趣的知识,因为std::array、std::vector和std::string实际上总是比原始数组更好的数据结构选择。关于std::unique_ptr唯一有意义的情况,我能想到的是,当您使用一个类C的API返回一个原始指针,指向您所拥有的堆数组时。“@StoryTeller@davidscallett我想我把它与
std::shared\u ptr
混淆了,因为我想共享一个
std::vector
的相同实例。谢谢你指出这一点。@StoryTeller说得对,对不起,我被要求声明值类型的移动构造函数
nothrow
,但这是为了调整向量大小时移动元素,而不是为了移动向量。隐式转换很好。设想C++实现一个类似于C的运行时接口。您可能会遇到类似(NSString::alloc())->autorelease()、在NSString、NSObject和NSSpecialString之间进行强制转换以及NSSpecialString等要求您采用类似于Microsoft IUnknown的QueryInterface的卑劣手段。我确信我们当前的C++可以自动完成这个过程。实际上,只有一个对象版本, UnQuyGPPT > <代码>操作符*()。阵列版本,
unique_ptr
具有
运算符[]()
。因此,与其返回第一个元素,
(*test)
甚至不应该编译。GCC给出:<代码>错误:“操作符*”(操作数类型是“STD::UnQuyPPTR”< <代码> >德米特里,我同意它是好的,这就是为什么Andrei Alexandrescu提供该选项作为“现代C++设计”的策略的原因;使用
显式
转换运算符,大多数情况下更不容易出错。但标准图书馆坚持更为谨慎的做法,我不能真的指责它。@DavidScarlett,好主意。我完全忘了它根本不应该起作用。酷!我同意隐式转换不是很好,调用
get()
也没什么大不了的。我想我只是被这本书所说的和编译器所做的与网络上可以找到的东西搞糊涂了。谢谢
test[0] = 5;
// 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()} {}
};
void f(ipiwdostbtetci_ptr<MyClass>);
...
std::unique_ptr<MyClass> p = ...
f(p);