鉴于声明,`std::unique<T> p;`,为啥`!p`是合法的,因为`std::unique<T>`没有记忆函数'operator !()'

Posted

技术标签:

【中文标题】鉴于声明,`std::unique<T> p;`,为啥`!p`是合法的,因为`std::unique<T>`没有记忆函数\'operator !()\'【英文标题】:Given the declaration, `std::unique<T> p;`,why `!p` is legail since there is no memory function 'operator !()' for `std::unique<T>`鉴于声明,`std::unique<T> p;`,为什么`!p`是合法的,因为`std::unique<T>`没有记忆函数'operator !()' 【发布时间】:2020-05-26 05:40:33 【问题描述】:

正如下面的代码,我不明白为什么!p 是合法的,因为std::unique&lt;T&gt; 没有成员函数'operator !()'。

由于std::cout &lt;&lt; p.get() &lt;&lt; std::endl; 是合法的,我认为p 是一个对象,而不是一个指针。所以我很困惑。

有人可以帮我一个忙吗?

std::cout << "unique ownership semantics demo\n";
  
      auto p = std::make_unique<D>(); 
      std::cout << p.get() << std::endl;  //I think p is an object, not an pointer.
      auto q = pass_through(std::move(p)); 
      assert(!p);  //Why it is legial?
      q->bar();   
   

【问题讨论】:

【参考方案1】:

!p 被编译时,编译器会隐式调用unique_ptr&lt;T&gt; 拥有的operator bool,然后将其取反。

更多详情请见here。

【讨论】:

如果我理解正确的话,如果我自己创建的相关类具有相应的成员函数,!my_object_name 将调用operator bool。我说的对吗? @sunshilong369 是的,你是对的。通常将此类运算符设为explicit 以防止不必要的转换。但即使在我给出的链接中描述的上下文中明确执行转换。 很高兴再次见到。感谢您的澄清。 又提出一个问题,为什么std::unique_prt&lt;T&gt; 不直接重载! 运算符? @sunshilong369 我不知道这不起作用的任何原因,但由于隐式转换规则是为希望隐式转换为 bool 的类设计的,因此没有必要。虽然在 C++11 之前,像这样的类会重载 operator !【参考方案2】:

!p 是合法的,因为有一个明确定义的函数可以将 unique_ptr 转换为 bool

见https://en.cppreference.com/w/cpp/memory/unique_ptr/operator_bool

explicit operator bool() const noexcept;

!p 被翻译为!(p.operator bool())

【讨论】:

【参考方案3】:

回答您的其他问题:

std::cout &lt;&lt; p.get() &lt;&lt; std::endl; 之所以有效是因为

get() 返回 unique_ptr 持有的指针 operator&lt;&lt; 具有接受 void* 指针作为输入的重载 任何指针都可以隐式转换为void*

p 确实是一个对象,而不是一个指针。但是get() 返回一个指针。

【讨论】:

以上是关于鉴于声明,`std::unique<T> p;`,为啥`!p`是合法的,因为`std::unique<T>`没有记忆函数'operator !()'的主要内容,如果未能解决你的问题,请参考以下文章

调整 std::vector<std::unique_ptr<T>> 大小的性能

来自 T* 的 std::unique_ptr<T> 的构造函数显式背后的原因是啥?

boost::ptr_vector 与 std::vector<std::unique_ptr<T>>? [关闭]

转发在C ++中声明隐藏的typedef

在 class<std::unique_ptr<B>> 中强制模板函数为 T=B*

两个 unique_ptr<T> 的无锁交换