2016-08-29 51 views
-1

我有三個文件,main.cpp,a.cp​​p和b.cpp。 main()函數只是在a.cpp中調用一個函數,然後在b.cpp中調用 - 我得到一個SIGSEGV。據我所知,它看起來像我的sort()使用的lambda函數是相互衝突的。編譯命令行順序很重要;如果我通過編譯文件:C++ 11 lambda運算符命名空間衝突

g++ -std=c++11 main.cpp a.cpp b.cpp 

代碼崩潰(我得到 「*** stack smashing detected ***: ./a.out terminated」),但如果我轉 「a.cpp」 和 「b.cpp」:

g++ -std=c++11 main.cpp b.cpp a.cpp 

運行好(我沒有說它是否「有效」,只是SIGSEGV vs無SIGSEGV)。

這裏是最小的代碼示例我可以生成三個文件:

main.cpp中:

extern void spud1 (void); 
extern void spud2 (void); 

int 
main (int argc, char **argv) 
{ 
    spud1(); 
    spud2(); 
} 

a.cpp:

#include <vector> 
#include <string> 
#include <algorithm> 

using namespace std; 

struct Database 
{ 
    int  pubdate; 
    string title; 
    string link; 
}; 

static vector <Database> database; 

void 
spud1 (void) 
{ 
    int  i; 

    for (i = 0; i < 20; i++) { 
     database.push_back ({}); 
    } 

    sort(database.begin(), database.end(), 
     [] (const Database& a, const Database& b) 
     { 
      return (a.pubdate > b.pubdate); 
     }); 
} 

b.cpp:

#include <vector> 
#include <string> 
#include <algorithm> 

using namespace std; 

struct Database 
{ 
    unsigned  serial; 
    double   calories; 
    double   carbs; 
    double   sodium; 
    double   sugar; 
}; 

static vector <Database> database; 

void 
spud2 (void) 
{ 
    int  i; 

    for (i = 0; i < 20; i++) { 
     database.push_back ({}); 
    } 

    sort(database.begin(), database.end(), 
     [] (const Database& a, const Database& b) 
     { 
      return (a.serial > b.serial); 
     }); 
} 

有tw o這樣的事情打擾了我:

  1. 沒有跡象表明工具鏈中發生了「不好的事情」;沒有編譯器或鏈接器的警告,並且我沒有辦法使模塊的本地模塊「struct Database」 - 如果我在它前面粘上「static」,我會得到一個錯誤:「a.cpp:13:1 :錯誤:只能爲對象和函數指定存儲類**`「

所以,我的問題是,我做錯了什麼,我該如何解決它? (即,爲什麼沒有警告,這是「假定」發生的?以及如何讓我的「數據庫」結構實際上對模塊是本地的? - 我的解決方法是使用不同的名稱,但我不高興與)

+0

將'struct Database'放入一個未命名的命名空間中,如果這些命名空間對於'.cpp'翻譯單元應該是私有的。 –

+0

正確。如圖所示,代碼是最低可重複性測試用例。編輯順序很重要。按照πάνταῥεῖ的建議使用未命名的命名空間,但我認爲這是一個混亂 - lambda操作符不應該泄漏我的內部(更重要的是,非EXPORTABLE)對象,對吧? – rkrten

+2

在重複,尤其是[這個答案](http://stackoverflow.com/a/6380073/440558)是最相關的,因爲它解釋了*爲什麼這是發生(打破ODR)。 –

回答

3

可以使結構聲明/定義私有的翻譯單元,通過將它們放入一個未命名的命名空間:

namespace { // <<<<<<<<<<<<<<<< 
    struct Database 
    { 
     unsigned  serial; 
     double   calories; 
     double   carbs; 
     double   sodium; 
     double   sugar; 
    }; 
} 

否則,鏈接器將使用什麼樣的第一個發現,不管你的拉姆達函數也是模塊本地的。


這是從同一個細微的錯誤教訓,我們花費在我們的生產代碼的調試3或4天。不好笑,不。

+0

哎呀!幸運的是,我能夠縮小到「在過去24小時內做出的改變」:-) – rkrten