我可以避免在初始化std :: initializer_list的过程中不使用原始指针进行复制吗?

时间:2019-02-25 15:00:05

标签: c++ shared-ptr initializer-list

比方说,我有几个本地声明的对象,我想使用基于范围的语法进行迭代。这似乎运行良好,但是似乎将本地对象放入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;
}

是否有一种方法可以遍历一组本地声明的对象,而无需复制它们或使用原始指针?

3 个答案:

答案 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),它将执行复制,并且编译器不会删除它们。

对于此任务,我会做其他事情。可能创建一个编译时可变参数模板类,该模板类以指向基础对象的指针为模板。让我知道您是否想要一些代码。