rkrten rkrten - 3 months ago 10
C++ Question

C++11 lambda operator namespace conflict

I have three files, main.cpp, a.cpp and b.cpp. The main() function just calls a function in a.cpp, and then in b.cpp -- and I get a SIGSEGV. As far as I can tell, it looks like the lambda functions used with my sort() are conflicting with each other. Compile command line order is important; if I compile the files via:

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


The code crashes (I get "
*** stack smashing detected ***: ./a.out terminated
"), but if I switch "a.cpp" and "b.cpp":

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


it runs fine (I'm not saying anything about whether it "works" or not, just SIGSEGV vs no-SIGSEGV).

Here's the smallest code samples I could generate for the three files:

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);
});
}


There are two things that bother me about this:


  1. there's no indication from the toolchain that "something bad" is happening; there are no compiler or linker warnings, and

  2. I have no way to make "
    struct Database
    " local to the module -- if I stick "static" in front of it I get an error: "a.cpp:13:1: error: a storage class can only be specified for objects and functions**`"



So, my question is, what am I doing wrong, and how can I get around it? (i.e., why is there no warning, is this "supposed" to happen? and how do I make my "Database" struct actually be local to the module? -- my workaround is to use different names, but I'm not happy with that.)

Answer

You can make the struct declarations/definitions private for the translation unit by putting them into an unnamed namespace:

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

Otherwise the linker will use what's found first, no matter if your lambda functions are module local as well.


That was learned from that same subtle bug, we spent on debugging 3 or 4 days in our production code. Not funny, no.