【问题标题】:compiler order with gcc 4.8.5gcc 4.8.5 的编译器顺序
【发布时间】:2017-02-17 08:42:23
【问题描述】:

我的 gcc 版本是 4.8.5

  • posix gcc 版本 4.8.5 20150623 (Red Hat 4.8.5-4) (GCC)

我有两个cpp文件:

  • 1.cpp 和 2.cpp

虽然1.cpp中有一个静态函数被2.cpp调用。 在大多数机器上,我们应该是这样的:

  • g++ 2.cpp 1.cpp

否则会导致编译错误或运行时错误。

但是,在我的gcc 4.8.5机器上,我必须使用“g++ 1.cpp 2.cpp”编译才能成功运行。

这是gcc4.8.5的属性吗?还是我的软件有问题,或者我用错了?

================================================ ===============

我的机器是centos7,安装在mac的virtulbox上。这是我的代码:


1.h

 #include <map>   
 using namespace std;

 class A {
    private:
        A();
        static A _instance;
        map<int, int> test_map;
    public:
        static A& get_instance();
        static void fun();
    };

1.cpp

#include <iostream>

#include "1.h"

using namespace std;

A A::_instance;

A::A() {
    cout << "A::A()\n";
}

A& A::get_instance() {
    cout << "A::get_instance()\n";
    return A::_instance;
    // static A instance;
    // return instance;
}

void A::fun() {
    cout << "A::fun()\n";
    get_instance().test_map[1];
}

main.cpp

#include <iostream>
#include "1.h"
using namespace std;

int test() {
    cout << "test()\n";
    A::fun();
    return 0;
}
int y = test();

int main() {
    cout << "main()\n";
    A::fun();
}

在大多数机器和我在网络上看到的东西中,我们应该这样编译: g++ main.cpp 1.cpp

但在我的机器上,我必须像这样编译: g++ 1.cpp main.cpp

我的机器或我的 gcc 有什么问题?

【问题讨论】:

  • 您能否提供示例代码和错误消息来澄清问题?例如。 static function in 1.cpp called by 2.cpp 没有意义(静态函数不能在它定义的文件之外调用)。
  • 感谢您的意见,我编辑了问题并添加了我的代码。期待您的解决方案。
  • 还请提供您看到的错误的详细信息。除非您依赖未定义的行为(例如静态构造函数的顺序),否则文件的顺序根本不重要。
  • 两种方式在所有机器上都会编译成功。在其他机器上,“g++ main.cpp 1.cpp”生成的可执行文件运行成功,而“g++ 1.cpp main.cpp”生成的文件会导致段错误;在我的机器中,rumtime 的行为者得到了相反的结果。
  • 就像你说的那样,我认为静态构造函数顺序的未定义行为导致了这种差异。而且我觉得应该用另一种方式来写单例的代码。

标签: gcc


【解决方案1】:

我认为您正面临static initialization order fiasco,这是一个经典的 C++ 错误。如果在调用A::_instance 的构造函数之前调用main.cpp 中的初始化函数test(),您的代码将访问未初始化的A::_instance::test_map 字段,这可能会导致分段错误。我建议您在需要时重写getInstance 以创建实例:

A *A::_instance;

A& A::get_instance() {
  cout << "A::get_instance()\n";
  if(!_instance)
    _instance = new A;
  return *A::_instance;
}

附带说明,我建议您使用AddressSanitizer 自动检测此类错误和类似类型的错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-09
    • 2013-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-06
    • 2020-09-08
    相关资源
    最近更新 更多