具有自定义指针类型的unique_ptr:*get() 和运算符*() 给出不同的输出
unique_ptr with custom pointer type: *get() and operator*() give different output
根据cpp首选项调用std::unique_ptr::operator*()
相当于调用*(std::unique_ptr::get())
。
但是,这两个电话都得到了不同的结果。这是我的代码:
#include <iostream>
#include <string>
#include <memory>
#include <fcntl.h>
#include <unistd.h>
struct file_descriptor
{
private:
struct closer;
public:
typedef int handle_type;
typedef closer closer_type;
constexpr static handle_type kInvalidHandle = -1;
public:
file_descriptor(int handle = kInvalidHandle) : handle_{ handle } { }
file_descriptor(std::nullptr_t) : file_descriptor{ } { }
operator int&() { return handle_; }
operator int() const { return handle_; }
int& operator*() { return static_cast<int&>(*this); }
int operator*() const { return static_cast<int>(*this); }
bool operator==(const file_descriptor& other) const
{ return (handle_ == other.handle_); }
bool operator!=(const file_descriptor& other) const
{ return !(*this == other); }
private:
struct closer
{
typedef file_descriptor pointer;
void operator()(pointer handle) const
{ ::close(*handle); }
};
int handle_;
};
using unique_file_ptr = std::unique_ptr<typename file_descriptor::handle_type,
typename file_descriptor::closer_type>;
unique_file_ptr managed_open(const std::string& path)
{
return { ::open(path.c_str(), O_RDWR), { } };
}
int main(int, char**)
{
auto handle = managed_open("/dev/random");
std::cout << "*handle : " << *handle << std::endl;
std::cout << "*handle.get(): " << *handle.get() << std::endl;
}
我的输出(此处为实时输出(:
*handle : 4198400
*handle.get(): 3
请注意,*handle.get()
返回正确的值,而*handle
则不返回。
为什么我得到不同的结果?
这是发生的事情。 unique_ptr<T, D>::get()
返回D::pointer
- 在您的情况下,从int
句柄构造的临时file_descriptor
。然后它的operator*
调用它的operator int&
,该返回对该临时存储handle_
的引用。
直接调用 *handle.get()
时,将在临时死亡之前使用它生成的int&
引用。
但是当你打电话给*handle
时,你打电话给handle.operator*()
,而又叫handle.get()
。operator*
的实现 ,一切都扩展了,变成这样:
int& operator*() {
file_descriptor temp(internal_pointer_);
int& result = temp.handle_;
return result;
}
该函数返回对临时成员的引用。该临时在右大括号处死亡,并且引用变得悬空,因此程序在其生存期结束后通过访问对象而表现出未定义的行为。
我建议你重新考虑解决方案。这里有一种可以说是更干净的方法:
#include <iostream>
#include <string>
#include <memory>
#include <stdexcept>
#include <utility>
#include <fcntl.h>
#include <unistd.h>
struct managed_file {
managed_file() noexcept {};
managed_file(const std::string& path)
: _handle { ::open(path.c_str(), O_RDWR) }
{
if (_handle == -1) {
throw std::runtime_error { std::string { "failed to open file " } + path };
}
}
managed_file(const managed_file&) = delete;
managed_file(managed_file&& other) noexcept
: _handle { other._handle }
{
other._handle = -1;
}
managed_file& operator=(const managed_file&) = delete;
managed_file& operator=(managed_file&& other) noexcept {
managed_file tmp { std::move(other) };
using std::swap;
swap(_handle, other._handle);
return *this;
}
virtual ~managed_file() noexcept
{
close();
}
void close() noexcept {
if (_handle != -1) {
::close(_handle);
_handle = -1;
}
}
const int& operator*() const noexcept {
return _handle;
}
private:
int _handle = -1;
};
managed_file managed_open(const std::string& path)
{
return managed_file { path };
}
using namespace std;
int main(int, char**)
{
cout << "opening" << endl;
auto handle = managed_open("/dev/random");
cout << "checking" << endl;
std::cout << "*handle : " << *handle << std::endl;
}
相关文章:
- 尝试重载输出运算符时,我无法遍历对象向量
- 字符串数组上的 sizeof 运算符以 C++ 为单位给出不同的输出
- 如何为流输出运算符提供重载<<模板'using'类型别名?
- 在C++中重载输入/输出运算符
- 重载 ostream << 运算符,指针作为参数,导致输出上的内存地址
- 如何调用继承的重载运算符<<并在派生类的输出中添加更多文本?
- 为什么带有逻辑和运算符以及增量运算符的 c++ 程序给出的输出与预期不同?
- 如何处理自定义输出运算符中的 iomanips?
- 使输出流式处理运算符适用于 boost::variant<std::vector<int>、int、double 的正确方法是什么>
- C 和 C++ 中运算符大小的不同输出
- 是否可以转换 c++ 运算符新输出?
- C++ - <<运算符重载,链表 - 地址而不是标准输出
- 如何输入和输出方括号运算符 []
- C++ 输出流运算符 <<() 中的字符何时加宽?
- 我使用箭头运算符打印出对象的变量值,并得到一些随机值作为输出
- 编译器将输出的流运算符<<解释为用于按位左移的二进制运算符<<
- 使用模板化运算符输出集合集合<<
- 重载运算符<<输出布尔值.为什么
- C++重载运算符<<输出地址
- 如何重载运算符<<输出模板内定义的向量?