c++ std::pair, std::vector & memcopy

8

从a的第一个元素的内存地址开始,复制myvect.size() * sizeof(foo)字节的数据是安全的吗?

std::vector<std::pair<T1, T2> > myvect

将其转换为数组

struct foo{
    T1 first;
    T2 second;
}

如果数组被分配的元素数量与向量大小相同,会怎样呢?
谢谢。

1
std::pair是一个结构体,标准规定编译器确定布局,但顺序必须保持不变。因此,在std::pair<char,char>实例中,您的编译器可能会决定在每个char后放置3字节的填充以获得最优对齐。因此,您不能假设连续的内存布局 - 故事结束。 - Matthieu N.
3个回答

8

不,包含T1T2的类不能保证与std::pair<T1,T2>具有相同的布局或对齐方式,至少在C++98中是这样(因为std::pair不是POD类型)。 在C++0x中情况可能会有所不同。


1
@Chris:标准布局(standard-layout)是指编译器没有插入任何意外的类,但标准布局类并不一定安全可复制。一个 RAII 类包含一个指向堆分配对象的指针,在销毁时释放并在赋值时克隆,这是标准布局但不是 POD,可能不应该使用 memcpy 进行复制。 - Steve Jessop
1
@Michael:只有当struct foo是POD类型时才可以。:-P(对于这个问题来说,这意味着T1T2也是。) - C. K. Young
3
这就是为什么不仅纯粹主义者对std::copy感兴趣 - 它可以复制非POD数据。 - Steve Jessop
1
@Chris:没错,我忽略了那个细节(其实我假设它们是POD类型,这是一种危险的假设)。但是如果它们不是POD,std::copy()仍然可以使用(只要该类型支持赋值)。所以我的“纯粹主义”观点是错误的 - 应该简单地使用它。希望优化会导致编译器生成memcpy()等效代码,如果类型是POD,则我将查看一些汇编输出以确定实践中是否真的发生这种情况。无论如何,输出很可能足够好,除非它不够好(对于这种泛泛而谈的说法满意吗?)。 - Michael Burr
2
实际上,一些编译器为std::copy()创建的代码比std::memcpy()更好——std::copy()的特化可以轻松受益于类型对齐限制。例如,std::copy<double*>可能在没有先前检查的情况下使用64位对齐读/写。 - MSalters
显示剩余4条评论

4

你没有问的问题的答案可能是 std::transform

struct pairToFoo {
    // optionally this can be a function template.
    // template<typename T1, typename T2>
    foo operator()(const std::pair<T1,T2> &p) const {
        foo f = {p.first, p.second};
        return f;
    }
};

std::transform(myvect.begin(), myvect.end(), myarray, pairToFoo());

或者使用std::copy,但是需要为foo提供一个接受一对参数的operator=。这假设您可以重新编写foo:
struct foo {
    T1 first;
    T2 second;
    foo &operator=(const std::pair<T1,T2> &p) {
        first = p.first;
        second = p.second;
        return *this;
    }
};

std::copy(myvect.begin(), myvect.end(), myarray);

std::transform()是我永远记不住的东西。从来没有。也许现在我公开说了,有时它会突然出现在我的脑海里。 - Michael Burr
1
std::transform 是你得到的东西,而不是 map 和 zipWith。所以也许如果每次你忘记了 transform,你就在 Haskell 中重新编写相关函数,那么你就会记住它。即使只是为了避免编写 Haskell。 - Steve Jessop

0
一般来说,不行。在某些平台/编译器/STL实现中可能可以,但无论如何都不要这样做。你会依赖于pair<>和vector<>的实现细节。
我自己曾经犯过依赖于vector<>是连续数组的罪过。为此,我深感懊悔。但对于pair<>... 就说不吧。

6
实际上vector<>保证是一个连续的数组。 - Fred Larson
现在已经普遍认可std::vector<T>是连续的(我认为C++的未来版本会明确规定),而且&vec[0]应该可以用作大小为vec.size()的数组。但是,对于像std::pair这样的非POD类型进行memcpy操作是有风险的。 - C. K. Young
即使在C++03中,您也可以得到宽恕... std::vector需要使用连续存储。 - Derrick Turk
@Seva:根据C++03草案标准23.2.5,"vector的元素是连续存储的,这意味着如果v是一个vector<T, Allocator>,其中T是除了bool以外的某种类型,那么对于所有的0 <= n < v.size(),它遵循 &v[n] == &v[0] + n 的等式。" - Fred Larson
一些关于连续的 std::vector<> 的更多信息链接:https://dev59.com/enVC5IYBdhLWcg3wliKe 和 http://herbsutter.wordpress.com/2008/04/07/cringe-not-vectors-are-guaranteed-to-be-contiguous/ - Michael Burr
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接