【问题标题】:C++ lambda function pass by reference problemC++ lambda 函数通过引用传递问题
【发布时间】:2020-12-05 13:25:12
【问题描述】:

我使用 lambda 函数将点云存储到向量的每个实例中。即使我通过引用传递向量,当我尝试访问向量的每个实例时,我也会收到此错误:

typename boost::detail::sp_member_access<T>::type boost::shared_ptr<T>::operator->() const [with T = pcl::PointCloud<pcl::PointXYZI>; typename boost::detail::sp_member_access<T>::type = pcl::PointCloud<pcl::PointXYZI>*]: Assertion `px != 0' failed.

我的代码:

int size_ = 2;
std::vector<Cloud::Ptr> vector_cloud(size_);
for(int i=0; i<size_; i++)
{
    Cloud::Ptr cloud_(new Cloud);
    vector_cloud.push_back(cloud_);
}
auto fonk1 = [ &vector_cloud, size_]()
        {

            for(int i=0; i<size_; i++)
            {
                std::cout << "for debug" << std::endl;
                Point p;
                p.x = 0;
                p.y = 0;
                p.z = 0;
                p.intensity = 0;
                vector_cloud[i]->points.push_back(p);
            }
        };
fonk1();
std::cout << "Cloud size: " << vector_cloud[0]->size() << std::endl;

不是编译错误,输出是:

for debug

当我尝试推动一个点时,我收到了这个错误。 Cloud::Ptrpcl::PointCloud&lt;pcl::pointXYZI&gt;::PtrPointpcl::PointXYZI

即使我也删除了这些行:

    for (int i=0; i<2; i++) {
    Cloud::Ptr cloud(new Cloud);
    vector_cloud_frustums.push_back(cloud);
}

错误是一样的。

【问题讨论】:

  • CloudCloud::Ptr 是什么?可以发minimal reproducible example 吗?
  • 另一个非常有趣的 UB 案例。即使没有开启优化,有趣的事情也会发生。请参阅我的答案中的链接,我玩得很开心。取消注释最后一行会完全更改 之前 的输出
  • 我删除了相关行,错误是一样的。我更新了帖子。另外,我必须使用 Ptr 类型,因为我从事的是大型软件项目。
  • 如果删除这些行,那么向量中仍有 2 个元素不指向 Cloud 实例。稍等,我会更新答案
  • 查看编辑后的答案

标签: c++ function lambda pass-by-reference


【解决方案1】:

我假设 PointCloudCloud::Ptr 是这样的:

struct Point {
    int x,y,z,intensity;
};

struct Cloud {
    std::vector<Point> points;
    void push_back(const Point& p) { points.push_back(p);}
    using Ptr = Cloud*;
    size_t size() const { return points.size(); }
};

原来它们是别的东西,但这对于答案来说并不重要。


您的代码中的问题是您创建了一个大小为 2 的向量:

std::vector<Cloud::Ptr> vector_cloud(size_);

然后你在这个循环中再推 2 个元素:

for(int i=0; i<size_; i++)
{
    Cloud::Ptr cloud_(new Cloud);
    vector_cloud.push_back(cloud_);
}

前两个元素不指向Cloud 的实例。只有最后两个指向Cloud。然后在代码的最后一行:

std::cout << "Cloud size: " << vector_cloud[0]->size() << std::endl;

您取消引用向量中的第一个元素并导致未定义的行为。你可以在这个complete example看到效果。

结论:代码中的问题不在于 lambda 或捕获向量。坏线是最后一条。它调用未定义的行为。在上面的链接中,您可以取消注释该行以查看它如何影响其余代码的作用(即使其他代码之前出现)。

解决方法是先创建大小为 2 的向量,然后访问这些元素使用push_back,但不能同时使用两者。例如:

int size_ = 2;
std::vector<Cloud::Ptr> vector_cloud;  // empty vector !!
vector_cloud.reserve(size_);           // reserve space
for(int i=0; i<size_; i++)
{
    Cloud::Ptr cloud_(new Cloud);
    vector_cloud.push_back(cloud_);    // push elements
}

PS 您很可能不需要代码中的任何指针。使用std::vector&lt;Cloud&gt; 而不是std::vector&lt;Cloud*&gt;,除非有引入间接级别的理由。如果有,请使用智能指针。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多