Commenting out some lines of never executed function definition fixes it though. How come?
Full minimal example I've ended up with while deleting unrelated code below.
int main() {
auto tList = tokenize();
tList.front()->~Token(); //hangs forever if the code 10 lines above is not commented, normally I'll have pop_front() here
cout << "never gets printed";
return 0;
}
Normally I'll have
tList.pop_front()
instead of
tList.front()->~Token();
it's here just to demonstrate it more explicitly
Promised code: (also on https://gist.github.com/anonymous/3b8fa11e90c617b35623ba5432050c3e#file-main-cpp-L68)
tokenizer.h
#include <list>
#include <memory>
using namespace std;
#ifndef SGREP_TOKENIZER_H
#define SGREP_TOKENIZER_H
class Token {
public:
virtual ~Token() = default;
virtual bool isChar() const {
return false;
}
};
using TTokenList = list<unique_ptr<Token>>;
TTokenList tokenize ();
#endif //SGREP_TOKENIZER_H
tokenizer.cpp
#include <iostream>
#include <cctype>
#include <string>
#include "tokenizer.h"
using namespace std;
class Char : public Token {
char value;
public:
Char (char value) : value(value){};
bool isChar() const override {
return true;
}
};
TTokenList tokenize () {
TTokenList tList;
tList.push_back(make_unique<Char>('h'));
return tList;
}
main.cpp
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <exception>
#include "tokenizer.h"
using namespace std;
class SyntaxError : public exception {};
class Regex {
public:
virtual size_t match_part(const string& str, size_t begin, size_t maxLen, vector<size_t>& groups) = 0; // groups is a vector of begin,end indices of matched groups (ParenRegexes) (to be able to recreate substrings)
virtual ~Regex() = default;
};
class Char : public Regex {
protected:
vector<char> characterRanges; // pairs -> lower and upper inclusive bound of matching a character (even lower, odd upper), size is always divisible by 2
public:
Char(TTokenList& t, size_t& groupCount) {}
size_t match_part(const string& str, size_t begin, size_t maxLen, vector<size_t>& groups) override {
return 1;
}
};
class SeqRegex: public Regex {
unique_ptr<Regex> a;
public:
SeqRegex(TTokenList& t, size_t& groupCount);
size_t match_part(const string& str, size_t begin, size_t maxLen, vector<size_t>& groups) override { // maxLen by nemelo byt 0:
return 1;
}
};
class OrRegex: public Regex {
SeqRegex a;
public:
OrRegex(TTokenList& t, size_t& groupCount) : a(t, groupCount) {}
size_t match_part(const string& str, size_t begin, size_t maxLen, vector<size_t>& groups) override {
return 1;
}
};
SeqRegex::SeqRegex(TTokenList& t, size_t& groupCount) {
if (t.front()->isChar()) { // Commenting out this portion of code fixes the forever hanging ..
a = make_unique<Char>(t, groupCount);
} else {
cerr << "syntax error, expected [^)]-*^|]" << endl;
throw SyntaxError();
} // ...commenting out up to this point
}
int main() {
auto tList = tokenize();
tList.front()->~Token(); //hangs forever if the code 10 lines above is not commented, normally I'll have pop_front() here
cout << "never gets printed";
return 0;
}
There are, in totality, maybe a dozen unique scenarios where it is appropriate to directly call an object's destructor using the ~T() syntax.
This is no such scenario.
If your intent is to delete the first token in the list, simply calling tList.pop_front() is sufficient.
Calling the destructor directly like you are is going to invoke undefined behavior when the std::unique_ptr object maintaining it later tries to delete it again. So you can't make guarantees about what will or won't happen when this code gets compiled/executed.
You have two classes called Char. They do not have the same definition. This is a violation of the one-definition-rule (ODR) and thus undefined behavior.
I'm just curious why you didn't immediately discover this when you merged the files together.
Related
I have to read patient data from a .csv file and using a decision tree determine, based on the data being read in for each patient, whether the tumor is Benign or Malignant.
I am really struggling with how to even start this. So far I have written code that reads from the .csv file and stores the data into a vector as shown below spreading over a few header and cpp files.
From what I gather, I can create a parent decision class and then each attribute I am to process are the children classes. Not sure if that makes sense. Please let me know.
Below you will find the attributes I am to process along with a graphical tree that shows how it is determined whether the tumor is Benign or Malignant that I need to base my code off of. I will also include a small sample of the .csv file.
Please could I get some guidance as how I am to do this. I am having the greatest difficulty with pointer notation. Any guidance will greatly be appreciated.
CSVLine.h
#ifndef CSVLINE_H
#define CSVLINE_H
#include <string>
#include <sstream>
#include <vector>
using namespace std;
class CSVLine
{
private:
vector<string> data;
public:
CSVLine() {}
CSVLine(const CSVLine& other)
{
data = other.data;
}
CSVLine operator = (const CSVLine& other)
{
data = other.data;
}
~CSVLine() {}
void parse(string line, char delimiter = ',');
string getString(int columnNumber);
int getInt(int columnNumber);
};
#endif
CSVLine.cpp
#include "CSVLine.h"
void CSVLine::parse(string line, char delimiter)
{
stringstream inLine(line);
string tempColumn = "";
while (getline(inLine, tempColumn, delimiter))
{
data.push_back(tempColumn);
}
}
string CSVLine::getString(int columnNumber)
{
return data[columnNumber];
}
int CSVLine::getInt(int columnNumber)
{
return atoi(data[columnNumber].c_str());
}
CSVReader.h
#ifndef CSVREADER_H
#define CSVREADER_H
#include <vector>
#include <fstream>
#include <iostream>
#include "CSVLine.h"
using namespace std;
class CSVReader
{
public:
CSVReader() {}
vector<CSVLine> read(string fileName);
};
#endif
CSVReader.cpp
#include "CSVReader.h"
vector<CSVLine> CSVReader::read(string fileName)
{
ifstream inputFile;
vector<CSVLine> lines;
inputFile.open(fileName.c_str());
string line = "";
while (getline(inputFile, line))
{
CSVLine csvLine;
csvLine.parse(line);
lines.push_back(csvLine);
}
return lines;
}
Here is what I would do.
First, I would translate the table of features to a higher-order macro:
#define FOREACH_FEATURE(OP) \
OP(1, SampleCodeNumber, int, -1) \
OP(2, ClumpThickness, int, -1) \
OP(3, UniformityOfCellSize, int, -1)
// Fill in the rest of the table of features here yourself
Then I would use this macro to generate a struct with all the features of a patient like this:
struct PatientData {
#define DECL_FEATURE(index, name, type, init) type name = init;
FOREACH_FEATURE(DECL_FEATURE)
#undef DECL_FEATURE
PatientData() {}
PatientData(CSVLine& src) {
#define READ_FEATURE(index, name, type, init) name = src.getInt(index-1);
FOREACH_FEATURE(READ_FEATURE)
#undef READ_FEATURE
}
};
Then I would construct a PatientData object from a CSVLine:
CSVLine line = ...;
PatientData patientData(line);
Then I would implement the decision tree as nested if-statements on the patientData object:
if (patientData.UniformityOfCellSize <= 2) {
// ...
} else {
// ...
}
This would get you started but you need to complete and possible extend the FOREACH_FEATURE macro and implement the decision tree...
Nodes and pointers approach
If you don't want to implement your tree like above, ditch the above code and instead do the following. Start by including a few files that we need and implement a Feature class:
#include <memory>
#include <functional>
struct Feature {
int index1;
int apply(CSVLine& line) const {return line.getInt(index1-1);}
};
and translate the table of features to Feature like this:
Feature SampleCodeNumber{1};
Feature ClumpThickness{2};
Feature UniformityOfCellSize{3};
// Fill in the rest yourself
We are going to use an std::function<bool(CSVLine)> to decide for the branch in the tree:
typedef std::function<bool(CSVLine&)> BranchCondition;
Overloading the comparison operator for a Feature and double to return a BranchCondition lets us neatly express BranchConditions:
#define DEF_FEATURE_OP(op) BranchCondition operator op (Feature f, double x) {return [f, x](CSVLine& line) {return f.apply(line) op x;};}
DEF_FEATURE_OP(<)
DEF_FEATURE_OP(<=)
DEF_FEATURE_OP(>)
DEF_FEATURE_OP(>=)
#undef DEF_FEATURE_OP
We also need to declare the return value of the classification:
enum class Severity {
Benign, Malign
};
As a base class for the decision tree we declare
class PatientClassifier {
public:
virtual Severity classify(CSVLine& p) const = 0;
virtual ~PatientClassifier() {}
};
and implement it for the trivial case of a constant value along with a function severity to construct it:
class ConstantClassifier : public PatientClassifier {
public:
ConstantClassifier(Severity v) : _value(v) {}
Severity classify(CSVLine&) const override {return _value;}
private:
Severity _value;
};
std::shared_ptr<PatientClassifier> severity(Severity v) {
return std::make_shared<ConstantClassifier>(v);
}
and for the branching case along with a function branch:
class BranchingClassifier : public PatientClassifier {
public:
BranchingClassifier(
BranchCondition f,
const std::shared_ptr<PatientClassifier>& onTrue,
const std::shared_ptr<PatientClassifier>& onFalse)
: _f(f), _onTrue(onTrue), _onFalse(onFalse) {}
Severity classify(CSVLine& p) const override {
return (_f(p)? _onTrue : _onFalse)->classify(p);
}
private:
BranchCondition _f;
std::shared_ptr<PatientClassifier> _onTrue;
std::shared_ptr<PatientClassifier> _onFalse;
};
std::shared_ptr<PatientClassifier> branch(
BranchCondition f,
const std::shared_ptr<PatientClassifier>& onTrue,
const std::shared_ptr<PatientClassifier>& onFalse) {
return std::make_shared<BranchingClassifier>(f, onTrue, onFalse);
}
and then we just build the tree like
auto decisionTree = branch(
UniformityOfCellSize <= 2.0,
severity(Severity::Benign),
severity(Severity::Malign));
CSVLine line;
auto result = decisionTree->classify(line);
Note: You don't need custom copy constructor and assignment operator for CSVLine. And the getInt method could be marked as const.
I am so confused right now...
Here is the code that I will be talking about:
main.cpp:
#include "CustomVector.h"
#include <iostream>
int main() {
CustomVector<int, 15> hello{};
std::cout << hello.size() << '\n';
return 0;
}
CustomVector.h:
#pragma once
template<typename T, int S>
class CustomVector {
private:
T arr[S];
int size;
public:
CustomVector() : arr{}, size{ S } {}
// Methods
int size() const {
return size;
}
};
As you can see I am trying to use the size() method that I have in my class definition, which there shouldn't be a problem with, right..? But when I try to use it in main.cpp and try to print it out to the console, it is giving me the compiler error which my question title has. Why could this be, this has never happened to me before. I would think there is some sort of "redefinition" somehow, but how could that be, there couldn't be a redefinition if it is in my own user-defined class?
I wrote a class template for an array data structure like so:
#pragma once
#include <cstdlib>
template<typename T, unsigned int N>
class CArray {
public:
CArray();
T& operator [] (unsigned int index);
private:
T *entries;
};
template<typename T, unsigned int N>
CArray<T, N>::CArray()
{
entries = (T *)malloc(N*sizeof(T));
}
template<typename T, unsigned int N>
T& CArray<T, N>::operator [] (unsigned int index) {
if (index >= N) {
throw ;
} else {
return entries[index];
}
}
I wrote a minimal wrapper class that stores string objects, like so:
#pragma once
#include <string>
using namespace std;
class CEntry
{
public:
CEntry();
const string & getSymbol() const;
void setSymbol(string);
protected:
string m_value;
};
Implementation:
#include "CEntry.hpp"
CEntry::CEntry() : m_value(""){
}
const string & CEntry::getSymbol() const {
return m_value;
}
void CEntry::setSymbol(string value) {
m_value = value;
}
When i execute the following main:
#include <iostream>
#include <string>
#include "CEntry.hpp"
#include "CArray.hpp"
int main(int argc, char** argv) {
CArray<CEntry, 2000> test;
test[0].setSymbol("asdf");
cout << test[0].getSymbol();
}
The program crashes with a segmentation fault.
Thread 1 received signal SIGSEGV, Segmentation fault.
0x00007ffad1783f2a in msvcrt!memmove () from C:\WINDOWS\System32\msvcrt.dll
I inspected the program and the crash happens directly in the line of CEntry, where m_value gets assigned to the passed value (in the setSymbol function).
I am using eclipse on windows. I inspected the m_value variable before assignment and it shows suspect values, e.g. 13451671603782742029 for the string length? Could it be that the CEntry object was initialized but not it's member variables?
I've tried researching but cannot figure out whats happening here, thanks in advance.
Your program is crashing because you are accessing unconstructed string objects.
When you use malloc to allocate memory, the memory is uninitialized and the objects you are trying to use have not been constructed. This is Undefined Behavior and, in this case, is causing the crash.
Is it possible to write const function with apply_visitor inside?
For example, this code compiles without errors:
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <boost/variant.hpp>
using namespace std;
typedef boost::variant<int,string> vTypeVariants;
struct vType_toN : boost::static_visitor<int>
{
int operator()(int& i) const {
return i;
}
int operator()(const string& str) const{
return str.length();
}
};
class vType{
public:
vType(const int& src) : data(src){}
vType(const std::string& src) : data(src){}
int getLength(){
return boost::apply_visitor(vType_toN(),data);
}
private:
vTypeVariants data;
};
int main(int argc, char ** argv)
{
vType x = string("2");
printf("L=%d",x.getLength());
return(0);
}
Unless you will add const to getLength():
int getLength() const{
return boost::apply_visitor(vType_toN(),data);
}
In such case an error with vast description (2 pages) appears complaining about problem with initializing first argument.
So, the question is: How to use apply_visitor inside const function?
Found out myself.
Forgot const before int in static_visitor class operator definition.
Maybe someone will find this useful as it was not easy to find this out (my original class is much bigger).
I'd like to compose two (or more) streams into one. My goal is that any output directed to cout, cerr, and clog also be outputted into a file, along with the original stream. (For when things are logged to the console, for example. After closing, I'd like to still be able to go back and view the output.)
I was thinking of doing something like this:
class stream_compose : public streambuf, private boost::noncopyable
{
public:
// take two streams, save them in stream_holder,
// this set their buffers to `this`.
stream_compose;
// implement the streambuf interface, routing to both
// ...
private:
// saves the streambuf of an ios class,
// upon destruction restores it, provides
// accessor to saved stream
class stream_holder;
stream_holder mStreamA;
stream_holder mStreamB;
};
Which seems straight-forward enough. The call in main then would be something like:
// anything that goes to cout goes to both cout and the file
stream_compose coutToFile(std::cout, theFile);
// and so on
I also looked at boost::iostreams, but didn't see anything related.
Are there any other better/simpler ways to accomplish this?
You do have the right design—if you want to do this purely within the stdlib.
One thing: instead of teeing to each streambuf on every output, implement it to use the same put area as one of the streambufs it's given, and copy to the others on overflow and sync. This will minimize virtual calls, which is one of the goals of how streambufs work.
Alternatively, and if you want to only handle stdout & stderr (which is common), run your program through the standard Unix tee program (or the equivalent on your platform), either by doing it yourself when invoking the program, or within the program by forking, setting up the streams as appropriate, etc.
Edit: You got me thinking, and I should know how to get this right. Here's my first approximation. (When this breaks, you get to keep both pieces.)
#ifndef INCLUDE_GUARD_A629F54A136C49C9938CB33EF8EDE676
#define INCLUDE_GUARD_A629F54A136C49C9938CB33EF8EDE676
#include <cassert>
#include <cstring>
#include <streambuf>
#include <map>
#include <vector>
template<class CharT, class Traits=std::char_traits<CharT> >
struct basic_streamtee : std::basic_streambuf<CharT, Traits> {
typedef std::basic_ios<CharT, Traits> Stream;
typedef std::basic_streambuf<CharT, Traits> StreamBuf;
typedef typename StreamBuf::char_type char_type;
typedef typename StreamBuf::traits_type traits_type;
typedef typename StreamBuf::int_type int_type;
typedef typename StreamBuf::pos_type pos_type;
typedef typename StreamBuf::off_type off_type;
basic_streamtee() : _key_buf(0) {}
basic_streamtee(Stream& a, Stream& b) : _key_buf(0) {
this->pubimbue(a.rdbuf()->getloc());
_set_key_buf(a.rdbuf());
insert(a);
insert(b);
}
~basic_streamtee() {
sync();
for (typename std::map<Stream*, StreamBuf*>::iterator i = _bufs.begin();
i != _bufs.end();
++i)
{
StreamBuf* old = i->first->rdbuf(i->second);
if (old != this) {
old->pubsync();
}
}
}
// add this functionality?
// streambufs would be unconnected with a stream
// easy to do by changing _bufs to a multimap
// and using null pointers for the keys
//void insert(StreamBuf* buf);
//void remove(StreamBuf* buf);
void insert(Stream& s) {
sync();
if (!_bufs.count(&s)) {
if (!_key_buf) {
_set_key_buf(s.rdbuf());
}
_bufs[&s] = s.rdbuf(this);
}
}
void remove(Stream& s) {
sync();
typename std::map<Stream*, StreamBuf*>::iterator i = _bufs.find(&s);
if (i != _bufs.end()) {
StreamBuf* old = i->second;
i->first->rdbuf(i->second);
_bufs.erase(i);
if (old == _key_buf) {
_set_key_buf(_bufs.empty() ? 0 : _bufs.begin()->second);
}
}
}
private:
basic_streamtee(basic_streamtee const&); // not defined
basic_streamtee& operator=(basic_streamtee const&); // not defined
StreamBuf* _key_buf;
std::map<Stream*, StreamBuf*> _bufs;
void _set_key_buf(StreamBuf* p) {
//NOTE: does not sync, requires synced already
_key_buf = p;
_update_put_area();
}
void _update_put_area() {
//NOTE: does not sync, requires synced already
if (!_key_buf) {
this->setp(0, 0);
}
else {
this->setp((_key_buf->*&basic_streamtee::pbase)(),
(_key_buf->*&basic_streamtee::epptr)());
}
}
#define FOREACH_BUF(var) \
for (typename std::map<Stream*, StreamBuf*>::iterator var = _bufs.begin(); \
var != _bufs.end(); ++var)
// 27.5.2.4.1 Locales
virtual void imbue(std::locale const& loc) {
FOREACH_BUF(iter) {
iter->second->pubimbue(loc);
}
}
// 27.5.2.4.2 Buffer management and positioning
//virtual StreamBuf* setbuf(char_type* s, std::streamsize n); // not required
//virtual pos_type seekoff(off_type off, std::ios_base::seekdir way,
// std::ios_base::openmode which); // not required
//virtual pos_type seekpos(pos_type sp, std::ios_base::openmode which); // not required
virtual int sync() {
if (!_key_buf) {
return -1;
}
char_type* data = this->pbase();
std::streamsize n = this->pptr() - data;
(_key_buf->*&basic_streamtee::pbump)(n);
FOREACH_BUF(iter) {
StreamBuf* buf = iter->second;
if (buf != _key_buf) {
buf->sputn(data, n); //BUG: ignores put errors
buf->pubsync(); //BUG: ignroes errors
}
}
_key_buf->pubsync(); //BUG: ignores errors
_update_put_area();
return 0;
}
// 27.5.2.4.3 Get area
// ignore input completely, teeing doesn't make sense
//virtual std::streamsize showmanyc();
//virtual std::streamsize xsgetn(char_type* s, std::streamsize n);
//virtual int_type underflow();
//virtual int_type uflow();
// 27.5.2.4.4 Putback
// ignore input completely, teeing doesn't make sense
//virtual int_type pbackfail(int_type c);
// 27.5.2.4.5 Put area
virtual std::streamsize xsputn(char_type const* s, std::streamsize n) {
assert(n >= 0);
if (!_key_buf) {
return 0;
}
// available room in put area? delay sync if so
if (this->epptr() - this->pptr() < n) {
sync();
}
// enough room now?
if (this->epptr() - this->pptr() >= n) {
std::memcpy(this->pptr(), s, n);
this->pbump(n);
}
else {
FOREACH_BUF(iter) {
iter->second->sputn(s, n);
//BUG: ignores put errors
}
_update_put_area();
}
return n;
}
virtual int_type overflow(int_type c) {
bool const c_is_eof = traits_type::eq_int_type(c, traits_type::eof());
int_type const success = c_is_eof ? traits_type::not_eof(c) : c;
sync();
if (!c_is_eof) {
char_type cc = traits_type::to_char_type(c);
xsputn(&cc, 1);
//BUG: ignores put errors
}
return success;
}
#undef FOREACH_BUF
};
typedef basic_streamtee<char> streamtee;
typedef basic_streamtee<wchar_t> wstreamtee;
#endif
Now, this test is far from complete, but it seems to work:
#include "streamtee.hpp"
#include <cassert>
#include <iostream>
#include <sstream>
int main() {
using namespace std;
{
ostringstream a, b;
streamtee tee(a, b);
a << 42;
assert(a.str() == "42");
assert(b.str() == "42");
}
{
ostringstream a, b;
streamtee tee(cout, a);
tee.insert(b);
a << 42 << '\n';
assert(a.str() == "42\n");
assert(b.str() == "42\n");
}
return 0;
}
Put it together with a file:
#include "streamtee.hpp"
#include <iostream>
#include <fstream>
struct FileTee {
FileTee(std::ostream& stream, char const* filename)
: file(filename), buf(file, stream)
{}
std::ofstream file;
streamtee buf;
};
int main() {
using namespace std;
FileTee out(cout, "stdout.txt");
FileTee err(clog, "stderr.txt");
streambuf* old_cerr = cerr.rdbuf(&err.buf);
cout << "stdout\n";
clog << "stderr\n";
cerr.rdbuf(old_cerr);
// watch exception safety
return 0;
}
You mention having not found anything in Boost.IOStreams. Did you consider tee_device?
I would write a custom stream buffer that just forwards data to the buffers of all your linked streams.
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <functional>
class ComposeStream: public std::ostream
{
struct ComposeBuffer: public std::streambuf
{
void addBuffer(std::streambuf* buf)
{
bufs.push_back(buf);
}
virtual int overflow(int c)
{
std::for_each(bufs.begin(),bufs.end(),std::bind2nd(std::mem_fun(&std::streambuf::sputc),c));
return c;
}
private:
std::vector<std::streambuf*> bufs;
};
ComposeBuffer myBuffer;
public:
ComposeStream()
:std::ostream(NULL)
{
std::ostream::rdbuf(&myBuffer);
}
void linkStream(std::ostream& out)
{
out.flush();
myBuffer.addBuffer(out.rdbuf());
}
};
int main()
{
ComposeStream out;
out.linkStream(std::cout);
out << "To std::cout\n";
out.linkStream(std::clog);
out << "To: std::cout and std::clog\n";
std::ofstream file("Plop");
out.linkStream(file);
out << "To all three locations\n";
}