gpt4 book ai didi

c++ - 为什么没有 unique_ptr::operator*() 的安全替代方案?

转载 作者:IT老高 更新时间:2023-10-28 22:08:18 25 4
gpt4 key购买 nike

std::vector 有成员函数 at() 作为 operator[] 的安全替代,因此可以应用边界检查并且没有创建悬空引用:

void foo(std::vector<int> const&x)
{
const auto&a=x[0]; // What if x.empty()? Undefined behavior!
const auto&a=x.at(0); // Throws exception if x.empty().
}

但是,std::unique_ptr 缺少相应的功能:

void foo(std::unique_ptr<int> const&x)
{
const auto&a=*x; // What if bool(x)==false? Undefined behavior!
}

如果 std::unique_ptr 有这样一个安全的替代方案,那就太好了,比如成员 ref()(和 cref() ) 它从不返回悬空引用,而是抛出异常。可能的实现:

template<typename T>
typename add_lvalue_reference<T>::type
unique_ptr<T>::ref() const noexcept(false)
{
if(bool(*this)==false)
throw run_time_error("trying to de-refrence null unique_ptr");
return this->operator*();
}

标准不提供这种东西有什么好的理由吗?

最佳答案

unique_ptr 专门设计为具有空状态检测功能的轻量级指针类(例如 optional 中的 A proposal to add a utility class to represent optional objects (Revision 3) 中所述)

也就是说,自 operator* 以来,您所要求的功能已经到位。文档状态:

// may throw, e.g. if pointer defines a throwing operator*
typename std::add_lvalue_reference<T>::type operator*() const;

指针类型is defined as

std::remove_reference<Deleter>::type::pointer if that type exists, otherwise T*

因此,通过您的自定义删除器,您可以执行任何即时操作,包括空指针检查和异常抛出

#include <iostream>
#include <memory>

struct Foo { // object to manage
Foo() { std::cout << "Foo ctor\n"; }
Foo(const Foo&) { std::cout << "Foo copy ctor\n"; }
Foo(Foo&&) { std::cout << "Foo move ctor\n"; }
~Foo() { std::cout << "~Foo dtor\n"; }
};

struct Exception {};

struct InternalPtr {
Foo *ptr = nullptr;
InternalPtr(Foo *p) : ptr(p) {}
InternalPtr() = default;

Foo& operator*() const {
std::cout << "Checking for a null pointer.." << std::endl;
if(ptr == nullptr)
throw Exception();
return *ptr;
}

bool operator != (Foo *p) {
if(p != ptr)
return false;
else
return true;
}
void cleanup() {
if(ptr != nullptr)
delete ptr;
}
};

struct D { // deleter
using pointer = InternalPtr;
D() {};
D(const D&) { std::cout << "D copy ctor\n"; }
D(D&) { std::cout << "D non-const copy ctor\n";}
D(D&&) { std::cout << "D move ctor \n"; }
void operator()(InternalPtr& p) const {
std::cout << "D is deleting a Foo\n";
p.cleanup();
};
};

int main()
{
std::unique_ptr<Foo, D> up(nullptr, D()); // deleter is moved

try {
auto& e = *up;
} catch(Exception&) {
std::cout << "null pointer exception detected" << std::endl;
}

}

Live Example

为了完整起见,我将发布两个额外的替代方案/解决方法:

  1. 通过 operator bool

    检查 unique_ptr 的指针
    #include <iostream>
    #include <memory>

    int main()
    {
    std::unique_ptr<int> ptr(new int(42));

    if (ptr) std::cout << "before reset, ptr is: " << *ptr << '\n';
    ptr.reset();
    if (ptr) std::cout << "after reset, ptr is: " << *ptr << '\n';
    }

    (这可能是处理问题的最隐秘方式)

  2. 另一种解决方案,虽然比较麻烦,is to use a wrapper type which takes care of the exception handling

关于c++ - 为什么没有 unique_ptr::operator*() 的安全替代方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32067213/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com