遍历带有指针和偏移量的stucts成员向量

时间:2019-01-30 13:03:02

标签: c++ pointers iteration heap-memory

我正在尝试通过不像我目前那样多地追踪指针来优化一段代码。我想创建一个常量偏移量以添加到存储的指针中,以获取下一个数据条目,请参见下面的代码。但是,数据位于类或结构的旁边,包含不同的数据类型。

所以我在下面的代码段中得到了正确的行为,即输出为1、2、3。

#include <iostream>
#include <vector>

// knows nothing about foo
class Readfoo
{ 
    private:
    int offset;
    double* pdouble;

    public:
    void SetPoint(double* apdouble, int aoffset)  
    {
        offset = aoffset;
        pdouble = apdouble;
    };

    const double& printfoo(int aidouble) const
    {
       return *(pdouble + offset*aidouble);
    };
};

// knows nothing about readFoo
struct foo
{ 
    int a[5];
    double b[10];
};

int main() 
{
    // populate some data (choose b [2] or other random entry.).
    std::vector<foo> bar(10);
    bar[0].b[2] = 1;
    bar[1].b[2] = 2;
    bar[2].b[2] = 3;

    // access b[2] for each foo using an offset.
    Readfoo newReadfoo;
    newReadfoo.SetPoint(&(bar[0].b[2]), sizeof(foo)/sizeof(double));
    for(int ii = 0; ii < 3; ii++)
    {        
        std::cout<<"\n"<<newReadfoo.printfoo(ii);
    }
    return 0;
}

我的问题有两个:

  1. 此代码确实合法,并且会产生未定义的行为吗?
  2. 如果不合法,有一种方法可以在不存储实际指针的情况下,通过foo访问b [2]进行迭代,在上述情况下,使用某种形式的常量偏移量(例如,将起始位置之间的位数相加)每个数据条目的地址。)?

1 个答案:

答案 0 :(得分:6)

不,这不是合法的C ++。仅当您停留在同一数组(或数组末尾的数组)内时,才定义指针算术。

  

expr.add#4

     

将具有整数类型的表达式J添加到指针类型的表达式P或从中减去时,结果的类型为P

     
      
  • (4.1)   如果P的值为空指针值,而J的值为0,则结果为空指针值。

  •   
  • (4.2)   否则,如果P指向具有n个元素的数组对象x[i]的元素x,则表达式P + JJ + P(其中J具有如果j的值x[i+j]指向(可能是假设的)元素0≤i+j≤n,而表达式P - J则指向{可能是假设的)元素x[i−j]如果是0≤i−j≤n

  •   
  • (4.3)   否则,行为是不确定的。

  •   

(4.1)不适用,因为您未在nullptr上进行操作。 (4.2)不适用,因为您正在使用double*,因此标准引号中的x必须是double数组,即结构的b成员。根据其余的(4.3),使用指针算法来限制边界是不确定的行为。

您要在此处进行的操作恰恰是一个好的编译器应该(并且将要)在后台进行的操作:

volatile double output;

void bar(std::vector<foo> bar, int innerOffset)
{
    for (foo& f : bar)
        output = f.b[innerOffset];
}

https://godbolt.org/z/S9qkTf

请注意反汇编如何执行所需的指针算术(因为编译器知道它在目标平台上有效)。这是最里面的循环:

.L3:
    movsd   xmm0, QWORD PTR [rax+24+rsi*8]
    add     rax, 104
    movsd   QWORD PTR output[rip], xmm0
    cmp     rdx, rax
    jne     .L3

104个字节恰好是foo的大小。 [rax+24+rsi*8]表达式可免费执行所有其他指针算法。