代码之家  ›  专栏  ›  技术社区  ›  Rishi Agrawal

从std::for\u each+lambda函数返回unique\u ptr

  •  -1
  • Rishi Agrawal  · 技术社区  · 7 年前

    我在返回std::moved unique\u指针到lambda时遇到问题。一旦将指针移到lambda函数,如何从lambda中收回所有权?

    在下面的代码中,我演示了我的问题。为了更好地解释这个问题,我从代码库中删除了一个片段,并将所有内容移到main中。第一个问题标记为“问题1”-我想了解我使用(*v)访问向量是否正确。

    代码创建一个由几个数字组成的向量,然后在该向量上迭代以标记位图中的位。我认为这些位标记正确,因为我能够在lambda中打印它们。在标记了这些位之后,我想要回所有权。我该怎么做?我需要返回指向调用者函数的位图指针。

    如何以标准方式从lambda获取所有权,而不是绕过传递的unique\u ptr或避免将指针移动到lambda。cpp17支持这一点吗?

    用g++-std=c++17编译代码

    #include <memory>
    #include <algorithm>
    #include <iostream>
    #include <vector>
    
    int main () {
    
      int increments = 10;
      int numberOfElements = 10;
    
      /* Create the vector */
      auto v = std::make_unique<std::vector<int>>(std::vector<int> (numberOfElements));
    
      /* QUESTION 1 - is (*v) the right way to access it or there is a better way. */
      std::generate((*v).begin(), (*v).end(), [n=0, increments]() mutable { n = n + increments; return n;});
    
      /* Print the generated elements */
      std::cout << "\nPrinting the generated elements ";
      std::for_each((*v).begin(), (*v).end(), [](int n) { std::cout<<" " << n;});
    
    
      /* Int find the maximum element */
      int maxElement = *(std::max_element((*v).begin(), (*v).end()));
      /* Making a bitmap of the elements */
    
      std::cout << "\nPrinting the maxElement " << maxElement;
      auto bitmap = std::make_unique<std::vector <bool>> (std::vector<bool>(maxElement + 1));
    
      /* Now setting all the elements in the vector to true in the bitmap. */
    
      for_each((*v).begin(), (*v).end(), [bmap = std::move(bitmap)](int n) { 
                                            (*bmap).at(n) = true; 
    
                                            if ((*bmap).at(n) == true) { 
                                              std::cout << "\nBit "<< n <<" marked";
                                            }
                                          });
    
      /******************************************************* 
       * Question 2 : I now need the ownership of bitmap back.
       * How to do it ?. Bitmap is now null after moving it to the lambda.
       */
      if (bitmap) {
        std::cout << "\nafter reset, ptr is not NULL ";
      } else if (bitmap == nullptr) {
        std::cout << "\nbitmap is null";
      }
    
    }
    
    1 回复  |  直到 7 年前
        1
  •  0
  •   Jarod42    7 年前

    问题1(*v)是访问它的正确方法还是有更好的方法。

    备选方案正在使用 -> 所以 v->begin() 而不是 (*v).begin() 。 但使用起来很奇怪 unique_ptr 对于 vector 。 您可以简单地执行以下操作:

    std::vector<int> v(numberOfElements);
    
    std::generate(v.begin(), v.end(),
                  [n=0, increments]() mutable { n = n + increments; return n;});
    
    std::cout << "\nPrinting the generated elements ";
    for (int e : v) { std::cout << " " << e; };
    
    int maxElement = *std::max_element(v.begin(), v.end());
    
    // ...
    

    问题2:我现在需要返回位图的所有权。怎么做?

    您不能使用lambda来完成这项工作,在您的情况下,通过引用捕获来完成这项工作(即使lambda拥有向量 for_each “阻止”不会):

    std::vector<bool> bitmap(maxElement + 1);
    
    for_each(v.begin(), v.end(), [&bmap](int n) { 
                                     bmap.at(n) = true;
                                     std::cout << "\nBit "<< n <<" marked";
                                 });
    assert(!bitmap.empty());
    if (bitmap.empty()) {
        std::cout << "\nbitmap is empty";
    } else if (bitmap == nullptr) {
        std::cout << "\nbitmap is NOT empty";
    }
    

    如果用自己的函子替换lambda,则可以执行以下操作

    class MyMarker
    {
    public:
        MyMarker(std::vector<bool>&& bitmap) : bitmap(std::move(bitmap)) {}
    
        MyMarker(const MyMarker&) = delete;
        MyMarker& operator =(const MyMarker&) = delete;
    
        void operator() (int n) const
        {
            bitmap.at(n) = true;
            std::cout << "\nBit "<< n <<" marked";
        }
    
        std::vector<bool> TakeBack() { return std::move(bitmap); }
    
    private:
        std::vector<bool> bitmap;
    };
    

    然后:

    std::vector<bool> bitmap(maxElement + 1);
    MyMarker myMarker(std::move(bitmap));
    assert(bitmap.empty());
    
    std::for_each(v.begin(), v.end(), myMarker);
    bitmap = myMarker.TakeBack();
    assert(!bitmap.empty());