【问题标题】:strange redefined symbols奇怪的重新定义符号
【发布时间】:2010-04-21 06:28:23
【问题描述】:

我将此标题包含在我自己的标题中:http://codepad.org/lgJ6KM6b
当我编译时,我开始收到这样的错误:

CMakeFiles/bin.dir/SoundProjection.cc.o:在函数“Gnuplot::reset_plot()”中: /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/include/g++-v4/new:105: `Gnuplot::reset_plot()' 的多重定义 CMakeFiles/bin.dir/main.cc.o:project/gnuplot-cpp/gnuplot_i.hpp:962:首先定义在这里 CMakeFiles/bin.dir/SoundProjection.cc.o:在函数“Gnuplot::set_smooth(std::basic_string, std::allocator > const&)”中: project/gnuplot-cpp/gnuplot_i.hpp:1041: `Gnuplot::set_smooth(std::basic_string, std::allocator > const&)' 的多重定义 CMakeFiles/bin.dir/main.cc.o:project/gnuplot-cpp/gnuplot_i.hpp:1041:首先定义在这里 CMakeFiles/bin.dir/SoundProjection.cc.o:/usr/include/eigen2/Eigen/src/Core/arch/SSE/PacketMath.h:41: `Gnuplot::m_sGNUPlotFileName' 的多重定义

我知道在这种混乱中很难看到,但是看看重新定义发生在哪里。它们发生在 /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.4/include/g++-v4/new:105 等文件中。新操作员如何获取有关 gnuplot 标头的信息?我什至无法编辑该文件。这怎么可能呢?我什至不确定如何开始调试它。我希望我已经提供了足够的信息。我无法在一个小项目中重现这一点。我主要只是在寻找有关如何找出发生这种情况的原因以及如何追踪它的提示。

谢谢。

【问题讨论】:

    标签: c++ include compiler-errors


    【解决方案1】:

    您显然违反了“单一定义规则”。您的头文件中有很多定义。其中一些是类或类模板(这很好),其中一些是内联函数或函数模板(这也很好),其中一些是“普通”函数和非模板的静态成员(这不好)。

    class foo;       // declaration of foo
    class foo {      // definition of foo
       static int x; // declaration of foo::x
    };
    
    int foo::x;      // definition of foo::x
    
    void bar();      // declaration
    void bar() {}    // definition
    

    一个定义规则说你的程序最多应该包含一个实体的定义。例外是类、内联函数、函数模板、类模板的静态成员(我可能忘记了一些东西)。对于这些实体,只要同一实体的两个定义不在同一翻译单元中,就可以存在多个定义。因此,将此头文件包含在多个翻译单元中会导致多个定义。

    【讨论】:

      【解决方案2】:

      看起来您包含冲突的标题。尝试检查您的包含路径。它们通常在-I 指令(至少在 gcc 中)或环境变量中定义。

      【讨论】:

        【解决方案3】:

        阅读编译器错误通常会有所帮助。你应该学会理解编译器告诉你什么。它抱怨符号被重新定义的事实是说你违反了单一定义规则。然后它甚至会告诉你符号是什么:

        class GnuPlot {
        //...
           GnuPlot& reset_plot(); // <-- declaration
        //...
        };
        //...
        Gnuplot& Gnuplot::reset_plot() { // <-- Definition
            nplots = 0;
            return *this;
        }
        

        您可以在程序中任意多次声明一个符号,但您只能定义一次(除非它是内联的)。在这种情况下,reset_plot 在包含标题的所有翻译单元中被编译和定义,违反了单一定义规则。

        最简单的解决方法是将其声明为内联,以便它可以出现在多个编译单元中,并让链接器稍后删除冗余副本(如果有的话)。

        还有一点问题是静态成员必须在类中声明并在翻译单元中定义(仅一次)。为此,您可以创建一个 .cpp 文件来定义这些变量(以及您不需要在标题中内联的任何函数/方法)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-12-14
          • 2015-04-11
          • 1970-01-01
          • 2013-08-16
          • 2012-04-20
          • 1970-01-01
          • 1970-01-01
          • 2019-05-09
          相关资源
          最近更新 更多