如何将指针数组作为 const 传递?

Vin*_*erl 4 c++ arrays pointers std parameter-passing

我想创建一个std::arrayof 指针,而不将指针指向的类型声明为 as const,以便我可以通过取消引用这些指针来更改数组指针指向的值。

所以我不想这样做:

#include <array>

int main()
{
    int a = 5;
    int b = 10;
    std::array<const int*, 2> arr = { &a, &b };     // with const
    *(arr[0]) = 20;                                 // Because this is not possible.
}
Run Code Online (Sandbox Code Playgroud)

但是这个:

#include <array>

int main()
{
    int a = 5;
    int b = 10;
    std::array<int*, 2> arr = { &a, &b };           // without const
    *(arr[0]) = 20;                                 // Because now it is possible.
}
Run Code Online (Sandbox Code Playgroud)

现在我想将此数组传递给函数,以便该函数无法通过取消引用这些指针来更改数组指针指向的值:

#include <array>

void test(const std::array<int*, 2>& arr)
{
    *(arr[0]) = 20;     // I want this to not be possible (in this example it is)
}

int main()
{
    int a = 5;
    int b = 10;
    std::array<int*, 2> arr = { &a, &b };
    test(arr);
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?因为 C 数组是可能的:

void test(int const * const * const arr)
{
    *(arr[0]) = 20;     // this is not possible
}

int main()
{
    int a = 5;
    int b = 10;
    int* arr[2] = {&a, &b};
    test(arr);
}
Run Code Online (Sandbox Code Playgroud)

我认为 C++ std 数组也应该可以。

非常感谢帮助。谢谢。

Tur*_*ght 9

不幸的是,你所要求的是不可能的。

这种情况下的根本问题是 const 仅在顶层传播。
因此,使指针成为常量只会使指针本身成为常量,而不会使所指向的对象成为常量。

对于任何包含指针的类都是如此,而不仅仅是std::arraygodbolt

std::array<int*, 2> arr = { &a, &b };
auto const& arrref = arr;
static_assert(std::same_as<decltype(arrref[0]), int* const&>); // not int const * const&!

struct Foo {
    int* ptr;
    auto& get() const { return ptr; }
};
Foo foo{&a};
auto const& fooref = foo;
static_assert(std::same_as<decltype(fooref.get()), int* const&>); // not int const * const&!
Run Code Online (Sandbox Code Playgroud)

为此,您需要一个指针类型,将其常量传播到指向的类型。

std::propagate_const(不幸的是,作为库基础 TS 的一部分,它仍然是实验性的)就是这样做的:它包装了一个类似指针的类型,以便它确实将 const 传播到指向的对象。

示例:神箭

using std::experimental::propagate_const;

void test(std::array<propagate_const<int*>, 2> const& arr)
{
    // ill-formed:
    //*arr[0] = 20;
}

int main()
{
    int a = 5;
    int b = 10;
    std::array<propagate_const<int*>, 2> arr = {&a, &b};
    test(arr);

    // well-formed
    *arr[0] = 42;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

与 C++20 一起使用的另一个选项是使用std::span.

std::span本质上只是一个指向数组的指针,因此您可以根据需要向元素类型添加尽可能多的常量(就像在 c 数组示例中将数组衰减为指针以添加常量一样)

示例:神箭

void test(std::span<int const* const> arr)
{
    // ill-formed:
    //*arr[0] = 20;
}

int main()
{
    int a = 5;
    int b = 10;
    std::array<int*, 2> arr = {&a, &b};
    test(arr);

    // well-formed
    *arr[0] = 42;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)