【问题标题】:C++11 lambda operator namespace conflict [duplicate]C ++ 11 lambda运算符命名空间冲突[重复]
【发布时间】:2017-01-06 00:19:59
【问题描述】:

我有三个文件,main.cpp、a.cpp 和 b.cpp。 main() 函数只是调用 a.cpp 中的一个函数,然后在 b.cpp 中调用一个函数——我得到一个 SIGSEGV。据我所知,与我的 sort() 一起使用的 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 与无 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);
        });
}

有两件事困扰我:

  1. 工具链中没有任何迹象表明正在发生“坏事”;没有编译器或链接器警告,并且
  2. 我无法将“struct Database”设置为模块本地——如果我在它前面加上“static”,我会收到错误:“a.cpp:13:1: error: a storage class can只为对象和函数指定**`"

所以,我的问题是,我做错了什么,我该如何解决? (即,为什么没有警告,这是“应该”发生的吗?如何使我的“数据库”结构实际上是模块的本地结构?-我的解决方法是使用不同的名称,但我不高兴与那个。)

【问题讨论】:

  • 如果 .cpp 翻译单元应该是私有的,请将 struct Database 放在未命名的命名空间中。
  • 正确。如图所示,代码是最小的可重现测试用例。编译顺序很重要。按照 πάντα ῥεῖ 的建议使用未命名的命名空间是可行的,但我认为这是一个问题——lambda 运算符不应该泄露我的内部(更重要的是,不可导出)对象,对吧?
  • 在副本中,尤其是this answer 是最相关的,因为它解释了为什么会发生这种情况(破坏 ODR)。

标签: c++ c++11 lambda


【解决方案1】:

您可以将结构声明/定义放入未命名的命名空间中,从而使翻译单元的结构声明/定义成为私有:

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

否则链接器将使用首先找到的内容,无论您的 lambda 函数是否也是模块本地的。


这是从同样的细微错误中学到的,我们在生产代码中花费了 3 或 4 天的时间进行调试。不好笑,不。

【讨论】:

  • 哎呀!幸运的是,我能够将其缩小为“过去 24 小时内所做的更改”:-)
猜你喜欢
  • 2012-12-18
  • 2021-11-22
  • 1970-01-01
  • 2017-07-09
  • 2011-08-06
  • 1970-01-01
  • 1970-01-01
  • 2010-09-20
相关资源
最近更新 更多