【问题标题】:array<> can’t simply swap pointers internallyarray<> 不能简单地在内部交换指针
【发布时间】:2014-08-22 08:17:54
【问题描述】:

对于用TR1引入STL的容器数组,我下面有个问题。

在《C++ 标准库 A Tutorial and Reference》一书的第 263 页:

但是请注意,数组 不能简单地在内部交换指针。出于这个原因,swap() 具有线性复杂性,并且迭代器和引用不会与其元素交换容器。

我想知道为什么 array 不能考虑交换指针的恒定开销?

【问题讨论】:

  • 可能是因为它没有用指针实现。
  • 它旨在成为 C 样式数组的零开销替代品。所以它直接保存数据。没有指向存储在其他地方的数据的指针,因此无法通过简单的指针交换来交换数据。

标签: c++ arrays c++11 complexity-theory swap


【解决方案1】:

您可能陷入了“C[++] 数组只是指针”的谬论。 不,它们不是。在某些情况下(主要是函数调用),数组衰减为指针。更正式地说,存在从数组到指向其第一个成员的指针的隐式转换。

但它们是完全不同的东西。指针是一个地址 - 通常为 4 或 8 个字节,具体取决于硬件。数组是一个接一个的对象序列。 sizeof 可以区分:

int main()
{
  int arr[5];
  int *p = arr;  // decay/implicit conversion happening here
  std::cout << sizeof arr << ':' << sizeof p;
}

这将在典型的 32 位 PC 上输出 20:4

如您所见,交换指针很快,但交换真正的数组却不是 - 您确实必须交换单个元素,因此需要的时间与元素数量成线性关系。 请注意,std::array 确实是一个数组的包装器。


一个不幸的 C 和 C++ 语法决定使混淆变得更糟——在函数参数类型上,可以使用数组语法,但“衰减”是在类型本身上执行的。这意味着这样的功能:

void foo(int a[]);
void bar(char b[40]);

实际上并不采用数组,它们采用指针。这些函数声明与这些完全相同

void foo(int *a);
void bar(char *b);

如此之多,以至于您实际上可以将一个用作另一个的前向声明:

#include <iostream>

void foo(int a[40]);

int main()
{
    int x = 42;
    foo(&x);
}

void foo(int *a)
{
    std::cout << a[0] << std::endl;
}

Live example

【讨论】:

    【解决方案2】:

    std::array 是一个模板类,它封装了一个static 数组,存储在对象本身内部,这意味着,如果您在堆栈上实例化该类,则静态数组将在堆栈上。 它的大小必须在编译时知道。因此它不能用指针来实现(即,必须在运行时分配的动态内存)。

    因此,std::array 的可能实现是:

    template<class _Ty, size_t _Size>
    class array {
      //...
      _Ty _Elems[_Size == 0 ? 1 : _Size];
    };
    

    如您所见,没有涉及指针,而是具体数组。

    您不能交换具体数组。因此,将一个数组的内容与另一个数组的元素逐个元素交换需要线性时间。

    【讨论】:

    • 您的“可能”实现中没有指针。这并不能解释为什么不可能用指针实现。
    • @juanchopanza Thanx,解决了这个问题。
    • 这样更好。将 -1 换成 +1。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多