如何从对象指针向量创建对象值向量?

时间:2013-09-27 11:52:58

标签: c++ c++11

“天真”的解决方案是;

std::vector<T> vector_of_objects;
vector_of_objects.reserve(vector_of_pointers.size());
for (T const * p : vector_of_pointers)
    vector_of_objects.push_back(*p);

上述内容似乎很麻烦,也许并不是很明显。

是否有一种解决方案至少效率不高,可能更快更直观?我认为C ++ 11可能有一个我不知道的解决方案......

6 个答案:

答案 0 :(得分:8)

将所有内容写入一行是否意味着更短的代码?否

在我看来,这两行更短更易读:

for (auto p : vector_of_pointers)

    vector_of_objects.emplace_back(*p);

函数std::for_each并不比基于范围的循环短,有时因为传递lambda表达式而变得更大。

函数std::transform甚至比std::for_each更长,但 transform 这个词有助于找出以下内容。

答案 1 :(得分:2)

你正在做正确的方法。另一种方法是使用内置算法库,如下所示:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

int main() {
    // Create a vector of pointers
    std::vector<int*> vptr;
    vptr.push_back(new int(1));
    vptr.push_back(new int(2));

    // Copy to vector of objects
    std::vector<int> vobj;
    std::for_each(vptr.begin(), vptr.end(), [&](int *n) { vobj.emplace_back(*n); });

    // Free the pointers
    std::for_each(vptr.begin(), vptr.end(), [&](int *n) { delete n; });

    // Print out the vector of objects
    std::copy(vobj.begin(), vobj.end(), std::ostream_iterator<int>(std::cout, " "));
    return 0;
}

答案 2 :(得分:2)

习惯的方式是使用std::transform

std::transform( vector_of_pointers.begin(),
                vector_of_pointers.end(),
                std::back_inserter( vector_of_objects ),
                []( T* p ) { return *p; } );

这是否比你写的“更好”是另一个 问题:它具有惯用性和优势的优点 实际上命名正在发生的事情(这使得代码略有不同 更清晰)。另一方面,“转型”非常非常 简单,所以它很容易在循环中识别,并且 编写这样的循环的新形式使得事情相当清楚 好。

答案 3 :(得分:1)

不,你必须在你的解决方案中调用copy-ctor,没有办法解决这个问题。

答案 4 :(得分:0)

std::vector<T*> vecPointers;
std::vector<T> vecValues;

for(size_t x=0;x<vecPointers.size();x++)
{
    vecValues.push_back(*vecPointers[x]);
}

我相信如果类型T是自定义对象,那么您需要为类T创建一个复制构造函数。

class T
{
    private:
        int someValue;
    public:
        T()
        {
        }
        T(const T &o)// copy constructor
        {
            someValue = o.someValue;
        }
        virtual ~T()
        {
        }
};

答案 5 :(得分:0)

在我看来,真正的问题是你是否经常这样做,因为值得在一个地方编写额外的代码来清理其他地方的代码。

我可以想象写一个允许你这样做的deref_iterator

std::vector<T> vector_of_objects{
    deref_iterator(std::begin(vector_of_pointers)), 
    deref_iterator(std::end(vector_of_pointers))};

现在,我们留下的问题是这是否真的比原始循环短。就简单的击键次数而言,它可能取决于你给出的名字。如果您不关心可读名称,可能是:

vector<T> v_o{d(begin(v_p)), d(end(v_p))};

简短的名字显然会让它变短,但我当然不会建议他们 - 如果我还没有输入,我就不知道这个世界是什么意思。较长的名称(需要重复几次)显然会增加更多的击键,但我无法想象有人认为可读性不值得。

无论如何,deref_iterator本身显然会占用一些代码。迭代器有足够的锅炉板,通常需要大约100行代码。让我们(有点随意)决定每次使用它时都会保存一行代码。在此基础上,你必须使用它100次才能收支平衡。

我不确定在整体代码的表征方面是否准确 - 迭代器的代码主要是锅炉,除了错字之外,没有太多可能真的出错。在大多数情况下,它应该包括正确的标题,并使用它,而不是几乎不必查看迭代器本身的代码。

在这种情况下,即使代码行数增加,我也可以接受它作为改进。写它只使用一次显然是一种损失,但我不认为它需要完全100次才有资格作为收支平衡。