使用带有成员函数的vector::data()链接打印不同的值作为指针算法

我有一个hello带有返回vector成员的方法的类。

我正在尝试使用vector::data()指针算法打印出值,但我面临未定义的行为。请参阅下面的示例:

class hello
{
public:
    std::vector<int> data()
    {
        return v;
    }

private:
    std::vector<int> v{1, 2, 3, 4};
};

int main(int argc, const char **argv)
{
    hello h;

    std::cout << "----------------------------" << std::endl;
    for (int i = 0; i < 4; i++)
    {
        std::cout << &*(h.data().data() + i) << std::endl;
        std::cout << *(h.data().data() + i) << std::endl;
    }

    int *sa = h.data().data();
    std::cout << "----------------------------" << std::endl;

    for (int i = 0; i < 4; i++)
    {

        std::cout << sa + i << std::endl;
        std::cout << *(sa + i) << std::endl;
    }

    return 0;
}

结果如下所示:

----------------------------
0x9e2ee0
1
0x9e2ee4
2
0x9e2ee8
3
0x9e2eec
4
----------------------------
0x9e2ee0
0
0x9e2ee4
0
0x9e2ee8
10289168
0x9e2eec
0

为什么*(sa + i)*(h.data().data() + i) 打印不同的值?


sa + i&*(h.data().data() + i)打印相同的内存地址,为什么我无法获得正确的数据只是使用这个内存地址(sa + i

回答

hello::data()返回一个vector 由值,这意味着它将返回一个临时副本hello::v,这将分配其自己的int阵列和从复制的值v

调用时h.data(),当它在调用的完整语句结束时超出范围时,该临时文件 vector将被销毁h.data()

所以,在你的第一个循环中:

for (int i = 0; i < 4; i++)
{
    std::cout << &*(h.data().data() + i) << std::endl;
    std::cout << *(h.data().data() + i) << std::endl;
}

这是完全有效的代码,因为每次调用返回的临时 数据在其内部数据被打印之前不会被销毁。vectorh.data()

但是,在您的第二个循环中:

int *sa = h.data().data();
for (int i = 0; i < 4; i++)
{
    std::cout << sa + i << std::endl;
    std::cout << *(sa + i) << std::endl;
}

在调用的语句中h.data()

int *sa = h.data().data();

临时 vector当它在声明的结尾范围,留下被破坏sa是一个悬摆指针,以释放内存,从而任何使用sa内循环是不确定的行为

sa + i并且h.data().data() + i 可能指向相同的内存地址,但前提是最后一次调用h.data() 碰巧创建了一个新的vector,它重用vector了第一个循环中临时s使用的相同内存块,但这不是保证。在任何情况下,sa都指向freed memory,因此内存块是否被重用并不重要,在vector进入第二个循环之前,拥有该内存块的内存块被销毁,释放内存。这就是为什么您无法访问数据,即使内存地址相同。

要解决这个问题,您需要更改hello::data()返回一个参考hello::v代替,则没有副本将被创建,如:

class hello
{
public:
    std::vector<int>& data() // <-- note the &
    {
        return v;
    }

private:
    std::vector<int> v{1, 2, 3, 4};
};

因此每次调用h.data().data()都会返回一个指向v内部数据的有效指针,从而sa不再是一个悬空指针。

或者,hello::data()返回一个指向v's 数据的指针,而不是返回(引用)v自身,例如:

class hello
{
public:
    int* data()
    {
        return v.data();
    }

private:
    std::vector<int> v{1, 2, 3, 4};
};

...

for (int i = 0; i < 4; i++)
{
    std::cout << &*(h.data() + i) << std::endl;
    std::cout << *(h.data() + i) << std::endl;
}

...

int *sa = h.data();
for (int i = 0; i < 4; i++)
{
    std::cout << sa + i << std::endl;
    std::cout << *(sa + i) << std::endl;
}


以上是使用带有成员函数的vector::data()链接打印不同的值作为指针算法的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>