C++就地转换向量类型

发布于 2025-01-01 10:25:48 字数 352 浏览 0 评论 0原文

是否可以在不创建新数据结构的情况下做到这一点? 假设我们

struct Span{
    int from;
    int to;
}
vector<Span> s;

直接从 s 获取整数向量,

vector<Span> s;

希望通过转换to

vector<int> s;

这样我们就可以删除/更改一些“from”、“to”元素,然后将其转换回

vector<Span> s;  

Is it possible to do this without creating new data structure?
Suppose we have

struct Span{
    int from;
    int to;
}
vector<Span> s;

We want to get an integer vector from s directly, by casting

vector<Span> s;

to

vector<int> s;

so we could remove/change some "from", "to" elements, then cast it back to

vector<Span> s;  

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

≈。彩虹 2025-01-08 10:25:48

这确实不是一个好主意,但我会告诉你如何做。

您可以通过这种方式获得指向整数的原始指针:

int * myPointer2 = (int*)&(s[0]);

但这确实是很糟糕的做法,因为您无法保证 span 结构没有任何 padding,因此,虽然今天它可能对我和你来说效果很好,但我们不能对其他系统说太多。

#include <iostream>
#include <vector>


struct Span{
    int from;
    int to;
};


int main()
{

    std::vector<Span> s;

    Span a = { 1, 2};
    Span b = {2, 9};
    Span c = {10, 14};

    s.push_back(a);
    s.push_back(b);
    s.push_back(c);


    int * myPointer = (int*)&(s[0]);

    for(int k = 0; k < 6; k++)
    {
        std::cout << myPointer[k] << std::endl;
    }

    return 0;
}

正如我所说,硬性重新解释转换通常会起作用,但非常危险,并且缺乏您通常期望从 C/C++ 获得的跨平台保证。

下一个更糟糕的事情是,它实际上会执行您要求的操作,但您永远不应该这样做。这是一种你可能会被解雇的代码:

// Baaaad mojo here: turn a vector<span> into a vector<int>:
std::vector<int> * pis = (std::vector<int>*)&s;

for ( std::vector<int>::iterator It = pis->begin(); It != pis->end(); It++ )
        std::cout << *It << std::endl;

注意我是如何使用指向向量的指针并指向向量对象 s 的地址的。我希望两个向量的内部结构是相同的,并且我可以像这样使用它们。对我来说,这是可行的,虽然标准模板可能幸运地要求这种情况,但对于模板化类来说通常并非如此(请参阅填充和模板专业化等内容)。

考虑复制一个数组(参见下面的参考文献 2)或仅使用 s1.from 和s[2].to。

相关阅读:

  1. std::vector 元素保证是连续的吗?
  2. 如何在 C++ 中将向量转换为数组

This is not really a good idea, but I'll show you how.

You can get a raw pointer to the integer this way:

int * myPointer2 = (int*)&(s[0]);

but this is really bad practice because you can't guarantee that the span structure doesn't have any padding, so while it might work fine for me and you today we can't say much for other systems.

#include <iostream>
#include <vector>


struct Span{
    int from;
    int to;
};


int main()
{

    std::vector<Span> s;

    Span a = { 1, 2};
    Span b = {2, 9};
    Span c = {10, 14};

    s.push_back(a);
    s.push_back(b);
    s.push_back(c);


    int * myPointer = (int*)&(s[0]);

    for(int k = 0; k < 6; k++)
    {
        std::cout << myPointer[k] << std::endl;
    }

    return 0;
}

As I said, that hard reinterpret cast will often work but is very dangerous and lacks the cross-platform guarantees you normally expect from C/C++.

The next worse thing is this, that will actually do what you asked but you should never do. This is the sort of code you could get fired for:

// Baaaad mojo here: turn a vector<span> into a vector<int>:
std::vector<int> * pis = (std::vector<int>*)&s;

for ( std::vector<int>::iterator It = pis->begin(); It != pis->end(); It++ )
        std::cout << *It << std::endl;

Notice how I'm using a pointer to vector and pointing to the address of the vector object s. My hope is that the internals of both vectors are the same and I can use them just like that. For me, this works and while the standard templates may luckily require this to be the case, it is not generally so for templated classes (see such things as padding and template specialization).

Consider instead copying out an array (see ref 2 below) or just using s1.from and s[2].to.

Related Reading:

  1. Are std::vector elements guaranteed to be contiguous?
  2. How to convert vector to array in C++
九命猫 2025-01-08 10:25:48

如果 sizeof(Span) == sizeof(int) * 2 (即 Span 没有填充),那么您可以安全地使用 reinterpret_cast;(&v[0]) 获取指向可迭代的 int 数组的指针。您可以使用 GCC 中的 __attribute__((__packed__)) 和 Visual Studio 中的 #pragma pack 保证每个编译器的无填充结构。

不过,有一种方法是有标准保证的。像这样定义 Span

struct Span {
    int endpoints[2];
};

endpoints[0]endpoints[1] 要求是连续的。如果您愿意,可以添加一些 from()to() 访问器以方便使用,但现在您可以使用 reinterpret_cast(&v [0]) 随心所欲。

但是,如果您要进行大量此类指针修改,您可能需要创建自己的类似向量的数据结构,该数据结构更适合这种处理,从而提供更多的安全保证这样你就可以避免射脚。

If sizeof(Span) == sizeof(int) * 2 (that is, Span has no padding), then you can safely use reinterpret_cast<int*>(&v[0]) to get a pointer to array of int that you can iterate over. You can guarantee no-padding structures on a per-compiler basis, with __attribute__((__packed__)) in GCC and #pragma pack in Visual Studio.

However, there is a way that is guaranteed by the standard. Define Span like so:

struct Span {
    int endpoints[2];
};

endpoints[0] and endpoints[1] are required to be contiguous. Add some from() and to() accessors for your convenience, if you like, but now you can use reinterpret_cast<int*>(&v[0]) to your heart’s content.

But if you’re going to be doing a lot of this pointer-munging, you might want to make your own vector-like data structure that is more amenable to this treatment—one that offers more safety guarantees so you can avoid shot feet.

清风不识月 2025-01-08 10:25:48

免责声明:我完全不知道你想要做什么。我只是做出有根据的猜测并在此基础上展示可能的解决方案。希望我能猜对,这样你就不用和愚蠢的演员们一起做疯狂的恶作剧了。

如果你想从向量中删除某个元素,你需要做的就是找到它并使用 擦除功能。您的元素需要一个迭代器,并且获取该迭代器取决于您对相关元素的了解。给定 std::vector v;:

  • 如果你知道它的索引:

    v.erase(v.begin() + idx);
    
  • 如果您有一个与您要查找的对象相同的对象:

    跨度分身;
    v.erase(std::find(v.begin(), v.end(), doppelganger));
    
  • 如果您有一个与您正在查找的对象相同的对象但想要删除所有相同的元素,你需要擦除-删除习惯用法:

    跨度分身;
    v.erase(std::remove(v.begin(), v.end(), doppelganger)),
            鬻());
    
  • If您有一些选择元素的标准:

    v.erase(std::find(v.begin(), v.end(),
                      [](Span const&s) { return s.from == 0; }));
    
    // 在 C++03 中,您需要一个单独的函数来执行条件
    boolstarts_from_zero(Span const&s) { return s.from == 0; }
    
    v.erase(std::find(v.begin(), v.end(),starts_from_zero));
    
  • 如果您有一些标准并且想要删除符合该标准的所有元素,则需要擦除删除又是成语:

    v.erase(std::remove_if(v.begin(), v.end(),starts_from_zero)),
            鬻());
    

Disclaimer: I have absolutely no idea about what you are trying to do. I am simply making educated guesses and showing possible solutions based on that. Hopefully I'll guess one right and you won't have to do crazy shenanigans with stupid casts.

If you want to remove a certain element from the vector, all you need to do is find it and remove it, using the erase function. You need an iterator to your element, and obtaining that iterator depends on what you know about the element in question. Given std::vector<Span> v;:

  • If you know its index:

    v.erase(v.begin() + idx);
    
  • If you have an object that is equal to the one you're looking for:

    Span doppelganger;
    v.erase(std::find(v.begin(), v.end(), doppelganger));
    
  • If you have an object that is equal to what you're looking for but want to remove all equal elements, you need the erase-remove idiom:

    Span doppelganger;
    v.erase(std::remove(v.begin(), v.end(), doppelganger)),
            v.end());
    
  • If you have some criterion to select the element:

    v.erase(std::find(v.begin(), v.end(),
                      [](Span const& s) { return s.from == 0; }));
    
    // in C++03 you need a separate function for the criterion
    bool starts_from_zero(Span const& s) { return s.from == 0; }
    
    v.erase(std::find(v.begin(), v.end(), starts_from_zero));
    
  • If you have some criterion and want to remove all elements that fit that criterion, you need the erase-remove idiom again:

    v.erase(std::remove_if(v.begin(), v.end(), starts_from_zero)),
            v.end());
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文