如何在 std 算法中使用 unique_ptr 的 transform_iterator
Posted
技术标签:
【中文标题】如何在 std 算法中使用 unique_ptr 的 transform_iterator【英文标题】:How to use transform_iterator of unique_ptr in std algorithm 【发布时间】:2018-04-02 20:31:24 【问题描述】:我正在尝试在 vector<unique_ptr>>.
的转换迭代器上调用 lower_bound
之前在 SO 上已提出类似问题。这个稍微复杂一点,其他问题的解决方案不容易适用。
问题是一样的。 std 实现在搜索期间将 __first
分配给 __middle
时调用 unique_ptr operator=。在此示例中,搜索转换对象列表 (int->double) 以定位等于或大于输入 (double) 的元素。
int main ()
vector<unique_ptr<int>>v
std::make_unique<int>(0),
std::make_unique<int>(1),
std::make_unique<int>(2),
std::make_unique<int>(3),
std::make_unique<int>(4),
;
auto transFunc = [](const unique_ptr<int>& m) -> double
return (*m) * 2.;
;
auto first = boost::make_transform_iterator(begin(v), transFunc);
auto last = boost::make_transform_iterator(end(v), transFunc);
auto i = lower_bound(first, last, 5.);
return 0;
我也尝试过使用 move_iterator 的。
auto transFunc = [](unique_ptr<int>&& m) -> double
return (*m) * 2.;
;
auto first = boost::make_transform_iterator(
make_move_iterator(begin(v)), transFunc);
auto last = boost::make_transform_iterator(
make_move_iterator(end(v)), transFunc);
似乎 boost 没有在转换后的迭代器中实现正确的价值。
该代码在 VS2013 中可以运行,但在 VS2015 或 GNU 中无法运行。
【问题讨论】:
【参考方案1】:lambda 不可复制,默认情况下transform_iterator
确实保留可调用的副本。
简单解决方案:std::ref
或 std::cref
:
Live On Coliru
#include <memory>
#include <boost/iterator/transform_iterator.hpp>
#include <vector>
int main ()
auto transFunc = [](const std::unique_ptr<int>& m) -> double return (*m) * 2; ;
std::vector<std::unique_ptr<int>> v;
v.push_back(std::make_unique<int>(0));
v.push_back(std::make_unique<int>(1));
v.push_back(std::make_unique<int>(2));
v.push_back(std::make_unique<int>(3));
v.push_back(std::make_unique<int>(4));
auto first = boost::make_transform_iterator(begin(v), std::cref(transFunc));
auto last = boost::make_transform_iterator(end(v), std::cref(transFunc));
auto i = lower_bound(first, last, 5.);
或者:
改为创建一个可复制的可调用对象:
struct double operator()(const std::unique_ptr<int>& m) const return (*m) * 2; ; transFunc;
Live On Coliru
奖金
Live On Coliru
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/phoenix.hpp>
#include <vector>
#include <memory>
using namespace boost::adaptors;
using namespace boost::phoenix::arg_names;
int main ()
std::vector<std::unique_ptr<int>> v(5);
boost::generate(v, [n=0]() mutable return std::make_unique<int>(n++); );
auto i = boost::lower_bound(
v |
indirected |
transformed(2. * arg1), 5.);
【讨论】:
刚刚意识到,如果我们使用 phoenix,我们不需要单独进行间接寻址:lower_bound(v | transformed((*arg1) * 2.0), 5.)
@CandyChiu 当然,虽然它也可能有助于扼杀性能以上是关于如何在 std 算法中使用 unique_ptr 的 transform_iterator的主要内容,如果未能解决你的问题,请参考以下文章
如何在构造函数中使用删除器初始化 std::unique_ptr?
如何将 std::sort() 与 std::unique_ptr<[]> 一起使用?
如何将 unique_ptr 与 std::copy 一起使用?
如何从 C++14 中的广义 lambda 捕获返回包含 std::unique_ptr 的 std::function?