微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C ++ std transform多次调用复制构造函数

如何解决C ++ std transform多次调用复制构造函数

在将地图元素复制到向量中的代码实现期间,我发现std::transform多次调用自定义类的复制ctor,尽管事先保留了向量大小。因此,我比较了执行此操作的不同方法,并发现最好的方法是简单的for循环。所以我的问题是:这些算法真的更昂贵吗?如果是这样,它们的优势是什么?还是少量元素无关紧要?这是我的测试代码

class A
{
public:
    A() {}
    A(int ai) : i(ai) {}
    A(A& a) : i(a.i) { std::cout << "copy ctor " << i << std::endl; }
    A(const A& a) : i(a.i) { std::cout << "copy const ctor " << i << std::endl; }
    A(A&& a) : i(std::move(a.i)) { std::cout << "move ctor " << i << std::endl; }    
    
    // I removed overloaded operators because they are not called here...

private:
    int i;
};

std::map<int,A> m;
m.insert(std::make_pair(0,A(7)));
m.insert(std::make_pair(1,A(3)));
m.insert(std::make_pair(2,A(1)));
 
std::vector<A> vec;

vec.reserve(m.size());
std::transform(m.begin(),m.end(),std::back_inserter(vec),[](const std::pair<int,A> & p) { return p.second; }); // 3 calls for each ctor

//... clean up and reserve vec
std::for_each(m.begin(),[&vec](const std::pair<int,A> & p) { vec.push_back(p.second); }); // 2 calls for each ctor

//... clean up and reserve vec
for (const auto & p : m) // 1 call for each ctor
{
    vec.emplace_back(p.second);
}

解决方法

"POSIXt"中的元素类型为std::map

在您的示例中,使用不带const的std::pair<const Key,Value>,因此您需要复制该对。这将在前两个解决方案中添加一个副本。如果将其更改为std::pair<int,A>,则在第一次迭代中可以看到2个构造函数调用,而在第二次迭代中只能看到一个(与for循环相当)。

对于第一次迭代,您现在有1个副本和一个动作。这是因为您的lambda需要复制A,然后back_inserter移动将其构造到向量中。通常,我不担心额外的举动,因为它们应该很便宜。

但是,您可以摆脱它。我们可以通过例如将返回类型指定为引用来强制lamba不复制A实例。因此,现在back_inserter插入时将不得不复制,仅此而已。

此版本的代码为每个解决方案的每个元素做一个副本:

std::pair<const int,A>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。