如何将指针的 std::array 作为 const 传递?

How to pass an std::array of pointers as const?

提问人:VincentSchaerl 提问时间:3/21/2023 最后编辑:VincentSchaerl 更新时间:3/21/2023 访问量:282

问:

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

所以我不想这样做:

#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.
}

但是这个:

#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.
}

现在我想将这个数组传递给一个函数,使这个函数不能通过取消引用这些指针来改变数组的指针所指向的值:

#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);
}

我该怎么做?由于 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);
}

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

非常感谢帮助。谢谢。

C++ 数组指 针 参数 传递 std

评论

0赞 JaMiT 3/21/2023
“既然 C 数组是可能的:” -- 你会如何使用 C 数组做到这一点?(注意:至少在我看来,允许数组衰减为指针并不是真正使用 C 数组。另外,可以转换为相同的指针,只是不能隐式转换。std::array
0赞 VincentSchaerl 3/21/2023
@JaMiT “How would you do this with C arrays?”——参见我上一个代码示例(有一个错误,我只是编辑了它)
0赞 JaMiT 3/21/2023
@VincentSchaerl “See my last code example” 我看到你的最后一个代码示例。但是,它接受指针,而不是数组。该函数不使用 C 样式数组,因此我不接受它作为使用 C 样式数组执行某些操作的演示。例如,给定一个适当初始化的 std::array<int*, 2> stdarr,您可以通过 test(stdarr.data()) 调用 test 的最后一个版本,并且看不到 C 样式的数组。我的观点是,C 样式数组也存在同样的问题;它通常被数组到指针的衰减所掩盖。test()test()
0赞 NathanOliver 3/21/2023
您可以创建一个类,该类接受任何容器并且仅公开 const 访问权限。这将需要一些代码来正确编写所有访问器,以使常量传播,但应该不会太糟糕。const_view

答:

0赞 Ryan 3/21/2023 #1

我认为没有办法实现您提到的特定要求。但是,通过以下方式传递取消引用的整数是可以的:

int modify(const int a)
{
    return a;
}

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

我无法在函数中修改其值。 虽然你可以简单地使用一个函数来处理这个问题,但它并不是那么开箱即用。

function A {
    change array to const int array
    pass const array into the function
}

或者稍微修改数组类中的运算符函数。

评论

0赞 Ryan 3/21/2023
它不是使用更少的内存吗?(不确定它是否实现)
0赞 Ryan 3/21/2023
哦,当然,我只是意识到。它正在使用指针。
9赞 Turtlefight 3/21/2023 #2

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

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

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

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&!

要做到这一点,您需要一个指针类型,该指针类型将其一致性传播到指向类型。

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

示例: godbolt

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;
}

另一个适用于 C++20 的选项是使用 std::span

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

示例: godbolt

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;
}

评论

0赞 Evg 3/21/2023
为什么有效而无效?std::span<int const* const>std::span<int const*>
1赞 Turtlefight 3/21/2023
@Evg你总是需要先从顶层添加 const - 你不能跳过一个级别,因为这会违反 const 的正确性 - 即 会起作用(将 const 添加到顶层) -> 将 const 添加到第二层(也有效)。但是,如果没有明确的强制转换,则不允许跳过一个级别并将 const 应用于较低的级别 - 裸指针的规则是相同的:godboltstd::span<int * const>std::span<int const * const>
0赞 Benjamin Buch 3/21/2023
@Turtlefight 该版本显然是目前最好的解决方案。你能稍微改变一下帖子,让它在顶部吗?还请附上您对 .谢谢!spanconst