【问题标题】:Segfault during compilation with arm gcc on class template在类模板上使用 arm gcc 编译期间的段错误
【发布时间】:2018-07-20 13:08:55
【问题描述】:

我有一个实现中值过滤器的类模板。模板参数是数据类型和过滤器长度。

使用基于 gcc 4.8.3 的 arm-none-eabi-g++ 进行编译时出现段错误。使用 Clang 5.0.1 或 Gcc 7.3.0 编译代码时不会发出警告。

我正在为 c++11 编译。

是我的代码有问题,还是真的是 gcc 错误?如果是错误,是否有方便的解决方法?即使不是错误,我也会感谢任何改进建议。

我能想到的可能是原因(尽管我认为它们都应该是允许的):

  • 在这个类中声明了一个结构,它的成员之一是指向结构类型本身的指针
  • 这个类有两个静态constexpr成员数据元素

代码

声明

// In MedianFilter.h
template <typename dType, int len>
class MedianFilter
{

public:
    dType read() { return xMed_; }
    dType update(dType x);

private:
    struct pair
    {
        pair* nextSmallest;
        dType xi;
    };

    static constexpr dType stopper_ {0};
    static constexpr int filterLen_ {len};

    pair buffer_[filterLen_] = {};
    pair* datpoint = buffer_;   
    pair small_ = {nullptr, stopper_};
    pair big_ = {&small_, stopper_};

    dType xMed_ {stopper_};

};

定义(在 .h 文件中)未显示

Main.cpp

#include <cstdint>
using std::uint16_t;

#include "MedianFilter.h"

int main() {
    MedianFilter<uint16_t, 7> filt;
    filt.update(0);
    return 0;
}

错误输出:

In file included from main.cpp:1:0: MedianFilter.h: In constructor
'constexpr MedianFilter<short unsigned int, 7>::MedianFilter()':
MedianFilter.h:22:7: internal compiler error: Segmentation fault 
class MedianFilter

Please submit a full bug report, with preprocessed source if appropriate. See <http://gcc.gnu.org/bugs.html> for instructions.

【问题讨论】:

  • “内部编译器错误”总是意味着编译器错误。
  • 使用 gcc x86 4.8.3 复制。一个最小示例:godbolt.org/g/H3qSTq(编译器实现者喜欢最小示例,在错误报告中没有 #include 指令。)
  • 感谢您提供的最小示例!我将使用它并提交错误报告。既然你已经查明了这个问题,我会看看我是否可以解决它。

标签: c++ templates gcc


【解决方案1】:

在@einpoklum 的回答中描述,这是在 gcc 4.9.1 中修复的编译器错误。解决方法相当简单——省略结构数组的大括号初始化并以其他方式实现您的设计意图。例如,您可以在结构的定义中提供默认的成员初始值设定项。

使用 C++11,可以在类定义中初始化类成员。编译器段错误是通过将此功能与结构数组一起使用来触发的,其中数组大小来自模板参数:

pair buffer_[filterLen_] = {};

AFAIK,从 C++11 开始,这个表达式应该用一个空的初始化列表对类成员数组进行聚合初始化。这相当于通过一个空列表 {} 来初始化每个数组元素,它对各个结构执行聚合初始化(同样使用一个空的初始化器列表)。

出于某种原因,此语法会导致编译器出现段错误。在 4.9.1 之前使用 gcc 的解决方法只是为了避免这种语法。

【讨论】:

    【解决方案2】:

    导致分段错误的不是您的代码,而是您的编译器发现了自己的分段错误并给您提供了更多信息。

    通常当进程执行分段错误时,即尝试以未经授权的方式访问内存段时,会调用默认信号处理程序,您会看到如下内容:

    Segmentation fault (core dumped)
    

    在进程退出时打印到标准错误流。但是一个进程(不仅仅是你的编译器,任何进程)都可以为信号安装自己的自定义处理程序。这样的处理程序可以访问 - 仔细 - 有关段错误上下文的附加信息并将其打印出来,以进行调试或允许您进行错误报告,如您提供的示例中所示。

    所以,请向维护您修改后的 GCC 编译器的人提交报告。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多