C++ 我们可以在std::array中使用传统的指针算法吗?

C++ 我们可以在std::array中使用传统的指针算法吗?,c++,arrays,c++11,c++-standard-library,C++,Arrays,C++11,C++ Standard Library,我想了解如何在指向std::array类元素的指针上使用老式的指针算法。毫不奇怪,以下代码可能无法编译: int main(int argc, char *argv[]) { double* data1 = new double[(int)std::pow(2,20)]; std::cout << *data1 << " " << *(data1 +1) << std::endl; delete data1; dat

我想了解如何在指向std::array类元素的指针上使用老式的指针算法。毫不奇怪,以下代码可能无法编译:

int main(int argc, char *argv[])
{
    double* data1 = new double[(int)std::pow(2,20)];
    std::cout << *data1 << " " << *(data1 +1) << std::endl;
    delete data1;
    data1 = NULL;

    double* data2 = new std::array<double, (int)std::pow(2,20)>;
    std::cout << *data2 << " " << *(data2 +1) << std::endl;
    delete data2;
    data2 = NULL;

    return 0;
}
作为练习,我想使用所有传统的指针算法,但不是指向老式的双数组,而是指向std::数组的元素。我的想法是这样的:

    double* data2 = new std::array<double, (int)std::pow(2,20)>;
指示编译器data2是指向堆分配的std::数组的第一个元素的指针

我被教导双*名=新双[尺寸];表示如下内容:«堆栈为指向一个double的指针分配内存并命名指针名称,然后堆分配一个大小为double的数组,然后将指针设置为指向数组的第一个元素。»由于上述代码未编译,我一定被教导了一些不正确的东西,因为相同的语法不适用于std::array

这引发了几个问题:

语句类型*name=new othertype[size];的实际含义是什么;? 如何使用std::array实现我想要的? 最后,如何使用std::unqiue_ptr和std::make_unique实现同样的效果? 我被教导双*名=新双[尺寸];表示如下内容:«堆栈为指向一个double的指针分配内存并命名指针名称,然后堆分配一个大小为double的数组,然后将指针设置为指向数组的第一个元素。»由于上述代码未编译,我一定被教导了一些不正确的东西,因为相同的语法不适用于std::array

您对该语句的看法是正确的,但请记住,其工作方式是new[]与new是不同的运算符。动态分配std::array时,调用单个对象为new,返回的指针指向std::array对象本身

您可以对std::数组的内容执行指针运算。例如,data2.data+1是指向data2[1]的指针。请注意,必须调用.data才能获得指向底层数组的指针


无论如何,不要动态分配std::array对象。尽可能避免动态分配,但如果需要,请使用std::vector。

您可以使用数据成员函数访问std::array的原始指针视图。但是,std::array的要点是您不必这样做:

int main(int argc, char *argv[])
{
    std::array<double, 2> myArray;
    double* data = myArray.data();
    // Note that the builtin a[b] operator is exactly the same as
    // doing *(a+b).
    // But you can just use the overloaded operator[] of std::array.
    // All of these thus print the same thing:
    std::cout << *(data) << " " << *(data+1) << std::endl;
    std::cout << data[0] << " " << data[1] << std::endl;
    std::cout << myArray[0] << " " << myArray[1] << std::endl;

    return 0;
}

广义的含义:

type* name = new othertype[size];
最后,我需要一个变量名,它是指向类型的指针,并使用new[]通过othertype的大小实例的连续分配来初始化它。请注意,这涉及强制转换,甚至可能无法工作,因为othertype和type可能不支持该操作。double的std::数组不等同于指向double的指针。它是一个指向std::数组的指针,句号,但是如果您想假装它是一个双精度的,并且您不介意您的程序是否由于未定义的行为而崩溃,那么您可以继续。编译器应该在这里警告您,如果没有警告,则警告不够严格

标准库容器都是关于迭代器的,而不是指针,尤其不是指针算术。迭代器比指针灵活得多,能够处理链表、树等奇特的数据结构,而不会给调用者带来很大的开销

有些容器(如std::vector和std::array)支持随机访问迭代器,这是对其内容的直接指针式访问:a[1]等等。仔细阅读任何给定容器的文档,因为有些人允许这样做,而许多人不允许这样做

请记住,变量和堆栈上分配的不一定是同一件事。优化编译器可以并且将把指针放在它想要的任何地方,包括寄存器而不是内存,或者如果它认为它可以在不破坏代码表达行为的情况下侥幸逃脱的话,则根本不会放在任何地方

如果您想要std::array(实际上是标准库容器),它几乎总是比C样式的数组好:

std::array<double, 2> data2;
如果你需要共享这个结构,你需要考虑使用STD::UnQuyJ-PTR的花费是否值得。这个东西的内存占用很小,复制它很简单,所以使用相对昂贵的内存管理功能是没有意义的

如果你绕过一个更大的结构,考虑使用一个引用代替,并将结构定位在最核心的数据结构中,这样就不需要通过设计来复制。 我们可以在std::array中使用传统的指针算法吗

是的,当然可以,但数组本身不是,它是一个对象。而是使用数组中的数据地址,通过std::array获得,如下所示:

std::array<double, 2>  data2 { 12.3, 45.6 };
double* raw_data2 = data2.data(); // or &(*data2.begin());
std::cout << *raw_data2 << " " << *(raw_data2 + 1) << std::endl;
还有这个。但是,您可能不需要真正使用指针算法,只需利用std::array的更好抽象来编写不同的代码即可

PS-
避免将显式内存分配用于new和Delete。请参阅关于此问题的。在您的情况下,您根本不需要堆分配—就像在常规数组中不需要堆分配一样。

当然,这些都是合法的:

template<class T, std::size_t N>
T* alloc_array_as_ptr() {
  auto* arr = new std::array<T,N>;
  if (!arr) return nullptr;
  return arr->data();
}
template<class T, std::size_t N>
T* placement_array_as_ptr( void* ptr ) {
  auto* arr = ::new(ptr) std::array<T,N>;
  return arr->data();
}
template<std::size_t N, class T>
std::array<T, N>* ptr_as_array( T* in ) {
  if (!in) return nullptr;
  return reinterpret_cast<std::array<T,N>*>(in); // legal if created with either above 2 functions!
}
// does not delete!
template<std::size_t N, class T>
void destroy_array_as_ptr( T* t ) {
  if (!t) return;
  ptr_as_array<N>(t)->~std::array<T,N>();
}
// deletes
template<std::size_t N, class T>
void delete_array_as_ptr(T* t) {
  delete ptr_as_array<N>(t);
}
令人震惊的是,如果使用得当,上述条款实际上是合法的。指向数组第一个元素的指针是可与整个std::数组互换的指针

您必须自己跟踪阵列大小

我不建议这样做。

std::array毕竟是一个STL容器

auto storage = std::array<double, 1 << 20>{};
auto data = storage.begin();
std::cout << *data << " " << *(data + 1) << std::endl;

新std::数组;不,不要这样做-事实上尽可能避免新的!还有,你到底需要指针算法做什么?std::array还提供了通常优于原始指针的迭代器。我可以问一下-为什么要执行原始指针算法?这应该是std::array data2,以避免混乱、不必要的新的和奇怪的转换为double*.data1+1*?你的意思是*data1+1 data1[1]?这都是真的,你告诉OP不要使用这个,警告在答案的末尾,是谁教你这么做的?代码在开头。。。