![](/img/trans.png)
[英]Lambda: Why are captured-by-value values const, but capture-by-reference values not?
[英]Why does accessing my capture-by-reference variable cause a segfault in my lambda function?
我將針對本地C / C ++ Meetup進行關於lambda表達式的演示,因此,我准備一些示例來演示lambda表達式如何解決某些任務。
示例之一是創建一個qsort
函數,該函數使用lambda表達式作為比較函數。 對於下面的sort_ascending()
這種簡單情況,它可以很好地工作,但是對於sort_descending()
,其中我包含一個計數器整數,該整數被引用捕獲,並隨每次對lambda表達式的調用而遞增,因此在第一次嘗試遞增時會遇到段錯誤櫃台。
我看了我可以找到的lambda表達式文檔,尤其是cppreference.cpp 。 據我所知,沒有理由為什么testcount
中的sort_descending
不在范圍之內: testcount
與對qsort_l
的調用位於同一堆棧幀中,並且當qsort_l
返回時不再使用捕獲testcount
的lambda表達式。
// -*- compile-command: "g++ -std=c++11 -ggdb -Wno-pmf-conversions -Wall -Werror -Weffc++ -pedantic -o minfail minfail.cpp" -*-
#include <stdlib.h>
#include <stdio.h>
void print_ints(const int* arr, int count)
{
for (int i=0; i<count; ++i)
{
if (i)
putchar(' ');
printf("%3d", arr[i]);
}
putchar('\n');
}
class Compar_Base
{
public:
virtual ~Compar_Base() { }
virtual int comp(const void* left, const void* right) const = 0;
static int compare(const void* left, const void* right, void* obj)
{
return static_cast<Compar_Base*>(obj)->comp(left,right);
}
};
template <typename Func>
class Compar_Concrete : public Compar_Base
{
Func &m_f;
public:
Compar_Concrete(Func f) : m_f(f) { }
virtual ~Compar_Concrete() { }
Compar_Concrete(const Compar_Concrete&) = delete;
Compar_Concrete& operator=(const Compar_Concrete&) = delete;
virtual int comp(const void* left, const void* right) const
{
return m_f(left,right);
}
};
/** Shiny, new qsort for lambda expressions. */
template <typename Func>
void qsort_l(void *base, size_t member_count, size_t member_size, Func f)
{
Compar_Concrete<Func> comp(f);
qsort_r(base, member_count, member_size, Compar_Base::compare, &comp);
}
void sort_ascending(int* intlist, int count)
{
auto f = [](const void* left, const void* right) -> int
{
return *static_cast<const int*>(left) - *static_cast<const int*>(right);
};
qsort_l(intlist, count, sizeof(int), f);
}
void sort_descending(int* intlist, int count)
{
int testcount = 0;
auto f = [&testcount](const void* left, const void* right) -> int
{
// Segmentation fault at this line:
++testcount;
return *static_cast<const int*>(right) - *static_cast<const int*>(left);
};
qsort_l(intlist, count, sizeof(int), f);
printf("\nIt took %d tests to complete the sort.\n", testcount);
}
int main(int argc, char** argv)
{
int ilist[] = {1,9,2,8,3,7,4,6,5};
int count = sizeof(ilist) / sizeof(int);
print_ints(ilist,count);
sort_ascending(ilist, count);
print_ints(ilist,count);
sort_descending(ilist, count);
print_ints(ilist,count);
}
我使用g ++版本4.8.4和5.4.0編譯了上面的代碼,結果相同(即segfault)。 通過查看代碼清單頂部聲明的compile-command
變量,可以看到正在使用的編譯器選項。
Func &m_f;
這是一個類成員,它是參考。 這是您的構造函數:
Compar_Concrete(Func f) : m_f(f) { }
m_f
成員被初始化為對構造函數的f
參數的引用。
不幸的是,該參數按值傳遞。 當構造函數結束並終止時, f
超出范圍並被銷毀,從而在類成員中留下了懸掛的引用。
隨后使用m_f
最終會取消引用無效的引用,並導致未定義的行為。 那至少是一個明顯的錯誤。
整個代碼充滿了類型不安全的泛型void *
,它們可能也隱藏了其他一些bug,但是尋找更多的bug毫無意義,因為這已經很容易成為問題了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.