资源句柄常量正确性

Resource handle const correctness

有时我在理解 const 正确性时遇到问题,尤其是当它是对象的逻辑常量时。假设我有一个 class 是某个资源的句柄。如果它是一个 const 句柄,那么我不想允许通过它修改资源。它不拥有这个资源,它有点像它的“视图”。如果我复制它,我不会创建新资源。

template<typename T>
class Handle
{
private:
    T *res = nullptr; // just placeholder value...

public:
    //constructors and other code...

    const auto& getRes() const  {return *res;}
    auto& getRes()              {return *res;}

};

这里我有一个问题。如果我从这个 const 句柄制作一个非常量副本,我可以修改资源。

void func(const Handle<int>& res)
{
    //res.getRes() = 10; // Error. good.
    auto res_copy = res;
    res_copy.getRes() = 10; // Not good.
}

我只是假设如果我将某些东西作为常量传递给函数,那么我应该能够以某种方式强制执行这种逻辑常量。或者也许我想错了。我知道标准库使用诸如 const-iterator / iterator 或 string-view 之类的东西,它们始终是 const 但不知道如何将其应用于这种情况。

我可以创建一个 ConstHandle 或将一个 Handle<int> 转换为 Handle<const int> 但是我必须在函数中指定句柄的常量和资源的常量,例如:

void func(const Handle<const int>& res)

如果我只是想将一个 const auto& handle 传递给函数,或者传递一个 const HandleType 概念,它可能不会很好地工作。也许我想多了,但我只是想在脑海中解决这个问题。

I just assume that if I pass something to a function as const, then somehow I should be able to enforce this logical constness.

这可能会导致令人惊讶的行为或无法执行的常量。如您所见,您只需复制句柄即可获得可变句柄。

这与常量指针不指向常量数据的问题相同。

我建议您遵循 std::span 的标准。如果您希望数据是常量,则需要使用 std::span<const int>

在你的情况下,如果你想对句柄指向的东西强制执行常量,那确实是 Handle<const int>


您也可以有一个 ConstHandle,但由于您已经有一个模板参数来指定 T,为了简单起见,我将使用它。为了便于使用,您也可以这样做:

template<typename T>
using ConstHandle = Handle<T const>;