比方说,我有几个本地声明的对象,我想使用基于范围的语法进行迭代。这似乎运行良好,但是似乎将本地对象放入initializer_list中,将执行复制。对于像std::shared_ptr
这样的对象(据我所知),增加引用计数是原子操作,这是一个坏消息。我认为可以避免的唯一方法是使用原始指针。
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> ptrInt1 = std::make_shared<int>(1);
std::shared_ptr<int> ptrInt2 = std::make_shared<int>(2);
/* in this loop, ptrInt1 and ptrInt2 are copied before they are binded
to ptrInt, this is ugly since the reference counter needs to temporarily
increased */
for(const std::shared_ptr<int>& ptrInt : {ptrInt1, ptrInt2}) {
std::cerr << *ptrInt << std::endl;
}
/* this solution works, but it feels somewhat ugly having to convert my smart
pointers to raw pointers to avoid the copying, perhaps there is a better
solution ?? */
for(const int* rawPtrInt : {ptrInt1.get(), ptrInt2.get()}) {
std::cerr << *rawPtrInt << std::endl;
}
return 0;
}
是否有一种方法可以遍历一组本地声明的对象,而无需复制它们或使用原始指针?
答案 0 :(得分:5)
您可以使用std::ref
来构建std::reference_wrapper
的列表。这会隐藏指针,让您像这样写列表
for(const std::shared_ptr<int>& ptrInt : {std::ref(ptrInt1), std::ref(ptrInt2)}) {
std::cerr << *ptrInt << std::endl;
}
答案 1 :(得分:3)
这是一个小的函数模板,扩展了@NathanOliver's answer并减少了一些打字。
#include <array>
#include <functional>
// No rvalues, thanks to @NathanOliver for pointing that out:
template <class ...T>
auto crefRange(const T&&...) = delete;
template <class ...T>
auto crefRange(const T&... args)
{
using First = std::tuple_element_t<0, std::tuple<T...>>;
return std::array<First, sizeof...(T)>{{std::cref(args)...}};
}
您可以实例化并通过调用它
for(const std::shared_ptr<int>& ptrInt : crefRange(ptrInt1, ptrInt2))
std::cerr << *ptrInt << std::endl;
如果使用不同的类型实例化它,则将失败,但是此限制与std::initializer_list
方法相同。
答案 2 :(得分:2)
不幸的是,std::initializer_list
非常不适合该任务。自
基础数组是类型为const T [N]的临时数组,其中 每个元素都已复制初始化...
(https://en.cppreference.com/w/cpp/utility/initializer_list),它将执行复制,并且编译器不会删除它们。
对于此任务,我会做其他事情。可能创建一个编译时可变参数模板类,该模板类以指向基础对象的指针为模板。让我知道您是否想要一些代码。