【问题标题】:Why is std::basic_string<char> segfaulting on my overloaded stream operator?为什么 std::basic_string<char> 在我的重载流运算符上出现段错误?
【发布时间】:2015-06-14 05:52:51
【问题描述】:

我正在尝试在 g++ 中编译和运行这个看起来无害的类,但程序在 malloc 或 memmove 上不断出现段错误。这里几乎没有发生任何事情。

使用 -g 编译并通过 gdb 运行时,我收到以下错误。这就是我对如何调试的了解程度。

由于某种原因,只有在从两个单独的文件编译时才会出现段错误。如果我将所有内容复制/粘贴到 main.cpp 中,它运行良好。

Windows/Cygwin g++ (GCC) 4.9.2:

程序收到信号SIGSEGV,分段错误。

0x61137eb5 in memmove() from /usr/bin/cygwin1.dll

..

程序收到信号SIGSEGV,分段错误。

0x610ef417 in muto::acquire(unsigned long) () from /usr/bin/cygwin1.dll

Windows/g++ 4.9.2-TDM:

程序收到信号SIGSEGV,分段错误。

0x777d27d0 in ntdll!RtlCompareMemoryUlong () from /c/Windows/SysWOW64/ntdll.dll

程序收到信号SIGSEGV,分段错误。 0x00007ffff7279ef5 in _int_malloc () from /lib64/libc.so.6 缺少单独的调试信息,使用:debuginfo-install glibc-2.17-55.el7_0.5.x86_64 libgcc-4.8.2-16.2.el7_0.x86_64 libstdc++-4.8.2-16.2.el7_0.x86_64 ..

CentOS 7/g++ (GCC) 4.8.2:

程序收到信号SIGSEGV,分段错误。

_int_malloc (av=0x7ffff75b6760 , bytes=29) at malloc.c:3281

3281 {

我正在使用以下标志进行编译:

-pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wswitch-default -Wundef -Wno-unused

我错过了什么?我还能在 gdb 中做些什么来帮助查明问题吗?

$ g++ main.cpp string_t.cpp -g -std=c++11 $DEBUG -o test.exe && ./test.exe

main.cpp

#include <iostream>

using std::cout;
using std::endl;

#include "string_t.h"

int main() {
   string_t a("test");

   cout << a << endl;

   return 0;
}

string_t.h

#include <cstdint>
#include <string>

class string_t {
std::basic_string<char> _base;

public:
   string_t(
      const char* s);

   friend std::ostream& operator<<(
      std::ostream& l,
      const string_t& r);
};

string_t.cpp

#include "string_t.h"

string_t::string_t(
   const char* s) :
   _base(s) {
}

std::ostream& operator<<(
   std::ostream& l,
   const string_t& r)
{
   l << r._base.c_str();

   return l;
}

【问题讨论】:

  • 你的代码用 g++ 编译得很好(在添加了缺少的 #include &lt;cstdint&gt; 之后)。
  • 该标准不要求实现为unsigned char 提供char_traits 的专门化(几乎可以肯定uint8_t 的类型定义为)。我很惊讶它会出现段错误,它在我自己的 mingw + gcc 主干构建上运行良好,但从技术上讲,你在无人区,你应该改变你的设计,而不是浪费时间试图找出哪里出错了。
  • 将所有的 uint8_t 更改为字符,它仍然是 segfauls 但在不同的地方。不过猜对了。
  • 您仍然缺少 #include &lt;iostream&gt; 包含在 string_t.h 中。
  • @Zhro 是的,如果您实际上发布了导致问题的确切代码,那么您会更快得到答案。关于char_traits 的观点仍然存在,这不是可移植的。

标签: c++ segmentation-fault cygwin


【解决方案1】:

您没有将&lt;ostream&gt; 包含到第二个翻译单元(string_t.cpp)中,因此无法找到重载解析

template<class CharT, class Traits>
basic_ostream<CharT,Traits>& operator << (basic_ostream<CharT,Traits>& os, const char* s);

当你调用时

l << r._base.c_str();

相反,string_t(const char* s) 被用作转换构造函数(它没有声明为explicit)来创建一个新的 string_t 对象和

std::ostream& operator<<(std::ostream& l, const string_t& r)

再次被调用,所以你最终得到了无限递归。

【讨论】:

  • 是的,这解决了它!我仍然不清楚发生了什么。 string_t.cpp 是如何在没有 std::ostream 的情况下编译的?
  • 我也想知道什么样的防御策略可以防止这个错误,面对庞大的代码库,如何追踪这个错误?这不是我第一次在脚上开枪,但这一次极具欺骗性。
  • 不幸的是 std::ostream 在范围内( 包括 ,其中包含 ostream 的前向声明 - 否则无法定义
  • 防御策略也许是,将带有一个参数的构造函数声明为显式(除非您知道需要隐式转换)。我通过查看 GCC 的中间表示(参见 -fdump-tree-gimple 选项)来追踪问题——但这有点“硬核”,也许你可以使用 GDB 来弄清楚会发生什么。
猜你喜欢
  • 1970-01-01
  • 2020-03-27
  • 1970-01-01
  • 1970-01-01
  • 2017-03-10
  • 1970-01-01
  • 2017-02-12
  • 2013-08-21
  • 1970-01-01
相关资源
最近更新 更多