英文:
Inherited CombinedStream object causing segmentation fault
问题
Here's the translated code portion you provided:
全部内容。我正在使用稍微修改过的 https://stackoverflow.com/a/1761027/2909854 中定义的类的版本,它允许我合并流,以便发送到合并流的任何内容都会发送到所有链接的流。此代码在除了两个问题之外运行良好:
1. 它引发了“deprecated-declarations”警告(该回答来自2009年)。
2. 如果我继承了`CombinedStream`对象,当我使用它时,会导致分段错误。
代码:
(以下为您提供的C++代码)
编译:
```bash
g++-13 inherited_stream.cpp -o inherited_stream.exe -std=c++20 -g
问题:
- 是否有可能
deprecated-declarations
警告指向的问题导致了这个问题?如果是的话,您能帮助我更新std::for_each...
行以解决这些问题吗? - 如果问题1的答案是否定的,有关为什么会出现分段错误的任何想法?
这是gdb
的回溯信息:
(以下为您提供的GDB回溯信息)
请告诉我您需要进一步的帮助。
英文:
all. I am using a slightly-modified version of the class defined at https://stackoverflow.com/a/1761027/2909854 which allows me to combine streams so that anything sent to the combined stream goes to all of the linked streams. This code works well for except for two issues:
- It causes
deprecated-declarations
warnings (that answer is from 2009). - If I inherit a
CombinedStream
object, when I use it, I get a segmentation fault.
Code:
#include <iostream>
// Needed for ComposeStream
#include <algorithm>
#include <vector>
#include <fstream>
#include <functional>
// A class that allows us to combine streams so that anything sent to the combined stream goes to all of them
// Modified from https://stackoverflow.com/a/1761027/2909854
class CombinedStream: public std::ostream
{
struct ComposeBuffer: public std::streambuf
{
void addBuffer(std::streambuf* buf)
{
bufs.push_back(buf);
}
virtual int overflow(int c)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
std::for_each(bufs.begin(),bufs.end(),std::bind2nd(std::mem_fun(&std::streambuf::sputc),c));
#pragma GCC diagnostic pop
return c;
}
private:
std::vector<std::streambuf*> bufs;
};
ComposeBuffer myBuffer;
public:
CombinedStream(): std::ostream(NULL)
{
std::ostream::rdbuf(&myBuffer);
}
void linkStream(std::ostream& out)
{
out.flush();
myBuffer.addBuffer(out.rdbuf());
}
};
class Parent
{
public:
Parent();
protected:
std::fstream m_outputFile;
CombinedStream m_outputFileAndCout;
};
class Child: protected Parent
{
public:
Child();
};
Parent::Parent()
{
std::string filePath = "test_file.test";
std::cout << "Opening " << filePath << "\n\n";
std::fstream m_outputFile(filePath, std::ios::app);
// Create a stream that combines cout and the process log
m_outputFileAndCout.linkStream(std::cout);
m_outputFileAndCout.linkStream(m_outputFile);
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
m_outputFileAndCout << "I'm working!" << std::endl;
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
}
Child::Child()
{
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
m_outputFileAndCout << "I'm crashing!" << std::endl;
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
}
int main()
{
Child object;
return 0;
}
Compilation:
g++-13 inherited_stream.cpp -o inherited_stream.exe -std=c++20 -g
Questions:
- Is it likely that the issues being pointed to by the
deprecated-declarations
warnings is causing this issue? If so, can you help me update thestd::for_each...
line to resolve these? - If no to question 1, any ideas why I get the segmentation fault?
Here is a gdb
backtrace:
(gdb) run
Starting program: /home/trackingtech/gateway/experiments/inherited_stream.exe
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/aarch64-linux-gnu/libthread_db.so.1".
Opening test_file.test
inherited_stream.cpp:72
I'm working!
inherited_stream.cpp:74
inherited_stream.cpp:79
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x0000aaaaaaaa46a4 in std::mem_fun1_t<int, std::basic_streambuf<char, std::char_traits<char> >, char>::operator() (this=0xffffffffed60, __p=0xffffffffecd8, __x=73 'I') at /usr/include/c++/13/bits/stl_function.h:1309
#2 0x0000aaaaaaaa416c in std::binder2nd<std::mem_fun1_t<int, std::basic_streambuf<char, std::char_traits<char> >, char> >::operator() (this=0xffffffffed60, __x=@0xaaaaaaacc8d8: 0xffffffffecd8)
at /usr/include/c++/13/backward/binders.h:165
#3 0x0000aaaaaaaa38c8 in std::for_each<__gnu_cxx::__normal_iterator<std::basic_streambuf<char, std::char_traits<char> >**, std::vector<std::basic_streambuf<char, std::char_traits<char> >*, std::allocator<std::basic_streambuf<char, std::char_traits<char> >*> > >, std::binder2nd<std::mem_fun1_t<int, std::basic_streambuf<char, std::char_traits<char> >, char> > > (__first=0xffffffffecd8, __last=0x0, __f=...) at /usr/include/c++/13/bits/stl_algo.h:3833
#4 0x0000aaaaaaaa2cdc in CombinedStream::ComposeBuffer::overflow (this=0xfffffffff158, c=73) at inherited_stream.cpp:23
#5 0x0000fffff7e9f5b4 in std::basic_streambuf<char, std::char_traits<char> >::xsputn(char const*, long) () from /lib/aarch64-linux-gnu/libstdc++.so.6
#6 0x0000fffff7e9159c in std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) ()
from /lib/aarch64-linux-gnu/libstdc++.so.6
#7 0x0000fffff7e91950 in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) () from /lib/aarch64-linux-gnu/libstdc++.so.6
#8 0x0000aaaaaaaa29b8 in Child::Child (this=0xffffffffef38) at inherited_stream.cpp:80
#9 0x0000aaaaaaaa2a50 in main () at inherited_stream.cpp:86
(gdb)
答案1
得分: 3
在Parent
构造函数中,您定义了一个全新且局部的变量m_outputFile
,并在其中使用它,而不是同名的成员变量。
这意味着在Parent
构造函数结束后,添加到组合流的缓冲区指针将变得无效,因为局部的m_outputFile
对象被销毁。
由于您硬编码了文件名,您应该使用构造函数初始化列表来初始化成员对象:
Parent::Parent()
: m_outputFile("test_file.test", std::ios::app) // 初始化成员变量
{
// 创建一个流,将cout和进程日志合并
m_outputFileAndCout.linkStream(std::cout);
m_outputFileAndCout.linkStream(m_outputFile);
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
m_outputFileAndCout << "I'm working!" << std::endl;
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
}
为了解决这个警告,而不是暂时禁用它,您可以使用lambda代替std::bind2nd
和std::mem_fn
:
std::for_each(bufs.begin(), bufs.end(),
[c](std::streambuf* buffer)
{
buffer->sputc(c);
});
或者更好的方法是使用范围for
循环:
for (auto buffer : bufs)
buffer->sputc(c);
(Note: The code in the response is presented in both English and Chinese as requested, but the actual code should remain in its original form without translation.)
英文:
In the Parent
constructor you define a brand new and local variable m_outputFile
and use it instead of the member variable of the same name.
That means the pointer to the buffer you add to the combined stream will become invalid after the Parent
constructor function ends, and the local m_outputFile
object is destructed.
Since you hard-code the filename you should use a constructor initializer list to initialize the member object:
Parent::Parent()
: m_outputFile("test_file.test", std::ios::app) // Initialize the member variable
{
// Create a stream that combines cout and the process log
m_outputFileAndCout.linkStream(std::cout);
m_outputFileAndCout.linkStream(m_outputFile);
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
m_outputFileAndCout << "I'm working!" << std::endl;
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
}
To solve the warning, instead of temporarily disabling it you can use a lambda instead of std::bind2nd
and std::mem_fn
:
std::for_each(bufs.begin(), bufs.end(),
[c](std::streambuf* buffer)
{
buffer->sputc(c);
});
Or perhaps better yet, use a range for
loop:
for (auto buffer : bufs)
buffer->sputc(c);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论