===Edit===
The problem is actually much simpler than this, any wrapped function that takes a table is causing the problem. If I wrap a function that takes luabind::object, and call that function with a table argument, then the gc causes an invalid free(). I'm starting to think that this may be some kind of crazy compilation/linking problem, as my compiled luabind dylib has lua symbols in it (resulting in two copies of those symbols, one in that library and one in my binary). Maybe I have duplicates of some lua static variables or something? I might just be grasping at straws here.
===Edit===
Using luabind 0.9 and gcc 4.2.1 on mac os x 10.6
I'm seeing what could (maybe?) be a problem with using a default_converter from lua tables.
I'm trying to define converters for various list-like types in my code, specifically std::vector. When I pass a table to a c++ method with such a default_converter, lua crashes with free() on an invalid pointer as soon as the garbage collector is called.
I'm probably missing something simple here, but I can't figure it out.
Thanks!
* Lua Code *
function first ()
-- Doesn't crash
-- t = TestClass(1, 3)
-- Crashes
t = TestClass({1, 2, 3})
print(t:get(0))
print(t:get(1))
print(t:get(2))
end
function second ()
print("About to call collectgarbage...")
collectgarbage()
print("Done calling collectgarbage!")
end
function test ()
first()
second()
end
* C++ Code *
#include <iostream>
#include <lua.hpp>
#include <luabind/luabind.hpp>
#include <luabind/operator.hpp>
using namespace std;
using namespace luabind;
namespace luabind {
template<typename ListType>
struct default_converter<std::vector<ListType> > : native_converter_base<std::vector<ListType> > {
static int compute_score(lua_State* L, int index) {
return lua_type(L, index) == LUA_TTABLE ? 0 : -1;
}
std::vector<ListType> from(lua_State* L, int index) {
std::vector<ListType> list;
for (luabind::iterator i(luabind::object(luabind::from_stack(L, index))), end; i != end; ++i)
list.push_back(luabind::object_cast<ListType>(*i));
return list;
}
void to(lua_State* L, const std::vector<ListType>& l) {
luabind::object list = luabind::newtable(L);
for (size_t i = 0; i < l.size(); ++i)
list[i+1] = l[i];
list.push(L);
}
};
}
class TestClass {
public:
TestClass(std::vector<int> v) : m_vec(v) {}
TestClass(int b, int e) {
for (int i = b; i <= e; ++i)
m_vec.push_back(i);
}
int get(size_t i) const {
return m_vec[i];
}
private:
std::vector<int> m_vec;
};
int main(int argc, char** argv) {
if (argc != 2) {
cout << "usage: " << argv[0] << " <scriptname>" << endl;
return -1;
}
std::string scriptName = argv[1];
lua_State* L = (lua_State*) lua_open();
luaL_openlibs(L);
open(L);
module(L)
[
class_<TestClass>("TestClass")
.def(constructor<std::vector<int> >())
.def(constructor<int, int>())
.def("get", &TestClass::get)
];
if (luaL_loadfile(L, scriptName.c_str()) || lua_pcall(L, 0, 0, 0)) {
cout << "Script error: " << lua_tostring(L, -1) << endl;
return -1;
}
call_function<void>(globals(L)["test"]);
lua_close(L);
return 0;
}
Yeah, I figured it out. Turns out that luabind didn't have any problems at all, except for the way it was built. The jam build system, on mac os x, causes the static lua library to be linked in with the luabind shared library, causing duplicate symbols (and duplicate static variables) when I link my final binary. It didn't have the entire lua library linked in though, so you still have to link liblua.a in again.
Take this explanation with a grain of salt, but it's my best guess; I'm not an expert at how the Mac OS X linker works. I do know that when I built luabind statically, everything works fine.
So, for anyone building lubabind in mac, build statically. There are also other problems with the jam built shared lib that you'd have to fix, like the fact that #executable_path is wrong. Static build was dead simple.
Related
Using
#include <execinfo.h>
one can access methods for unwinding the stack, at least on a most linux configurations. However, this allows one to fetch a char * to some NTBS (null terminated byte string) which shows some information, but not all of it, especially not:
file names
line numbers
function names
I have written a bash-script which can deduce a line number and a file using objdump and the text address of the instruction, however its use is tedious as I have to copy paste the address of multiple stack frames to it manually.
Given that g++ allows one to include debugging symbols with the -g command line option, how can I parse and access them in c++ programmatically? Debuggers like gdb and valgrind are also capable of accessing this information at runtime somehow: I'm assuming they use some library for that or if they implement it themselves export the functionality as an API. For example, valgrind defines some interesting function declarations in include/pub_tool_debuginfo.h. Unfortunately, I couldn't find anything else. I created this as a starting point:
#include <execinfo.h>
namespace stck {
class stacktrace_t {};
stacktrace_t stacktrace;
std::ostream &operator<<(std::ostream &out, stacktrace_t) {
out << "stacktrace:\n";
size_t max = 256;
void **stackframes = new void *[max];
size_t numel;
while ((numel = backtrace(stackframes, max)) >= max) {
max *= 2;
delete[] stackframes;
stackframes = new void *[max];
}
char **symbols = backtrace_symbols(stackframes, numel);
for(size_t i = 0; i < numel; ++i)
out << symbols[i] << '\n';
delete[] stackframes;
return out;
}
}
source: http://ideone.com/RWoADT
Are there any suggestions to append this code to also output human readable debugging information?
As a note, I'm implementing this for usage with mex, a matlab compiler which uses g[++|cc]. Whenever I'm using the functionality, the program is in a 'good' state, that is an error is detected but noting really has has happened; like a segmentation fault.
For example, one could check if the argument of sqrt is non-negative, and if not use the stck::stacktrace to show where this happened.
update
I think the information is not directly available at runtime (although I'm not sure), but is only available in the executable file, not in the executable text in memory. (Please correct me if I'm wrong.
Hence I think there is no way around parsing the executable file, for example via addre2line:
namespace stck {
std::string getstackframe(char *frame) {
std::string fr(frame);
size_t loc0 = fr.find("(");
size_t loc1 = fr.find(")");
std::stringstream ss;
ss << "addr2line -e " << fr.substr(0, loc0) << " -pfC " << fr.substr(loc0 + 2, loc1 - loc0 - 2);
FILE* pipe = popen(ss.str().c_str(), "r");
char buffer[128];
std::stringstream result;
while(!feof(pipe))
if (fgets(buffer, 128, pipe) != NULL)
result << buffer;
pclose(pipe);
return result.str();
}
class stacktrace_t {};
stacktrace_t stacktrace;
std::ostream &operator<<(std::ostream &out, stacktrace_t) {
out << "stacktrace:\n";
size_t max = 256;
void **stackframes = new void *[max];
size_t numel;
while ((numel = backtrace(stackframes, max)) >= max) {
max *= 2;
delete[] stackframes;
stackframes = new void *[max];
}
char **symbols = backtrace_symbols(stackframes, numel);
for(size_t i = 0; i < numel; ++i)
out << getstackframe(symbols[i]);
out << '\n';
delete[] stackframes;
return out;
}
}
I have the following Python snippet that I would like to reproduce using C++:
from itertools import count, imap
source = count(1)
pipe1 = imap(lambda x: 2 * x, source)
pipe2 = imap(lambda x: x + 1, pipe1)
sink = imap(lambda x: 3 * x, pipe2)
for i in sink:
print i
I've heard of Boost Phoenix, but I couldn't find an example of a lazy transform behaving in the same way as Python's imap.
Edit: to clarify my question, the idea is not only to apply functions in sequence using a for, but rather to be able to use algorithms like std::transform on infinite generators. The way the functions are composed (in a more functional language like dialect) is also important, as the next step is function composition.
Update: thanks bradgonesurfing, David Brown, and Xeo for the amazing answers! I chose Xeo's because it's the most concise and it gets me right where I wanted to be, but David's was very important into getting the concepts through. Also, bradgonesurfing's tipped Boost::Range :).
Employing Boost.Range:
int main(){
auto map = boost::adaptors::transformed; // shorten the name
auto sink = generate(1) | map([](int x){ return 2*x; })
| map([](int x){ return x+1; })
| map([](int x){ return 3*x; });
for(auto i : sink)
std::cout << i << "\n";
}
Live example including the generate function.
I think the most idiomatic way to do this in C++ is with iterators. Here is a basic iterator class that takes an iterator and applies a function to its result:
template<class Iterator, class Function>
class LazyIterMap
{
private:
Iterator i;
Function f;
public:
LazyIterMap(Iterator i, Function f) : i(i), f(f) {}
decltype(f(*i)) operator* () { return f(*i); }
void operator++ () { ++i; }
};
template<class Iterator, class Function>
LazyIterMap<Iterator, Function> makeLazyIterMap(Iterator i, Function f)
{
return LazyIterMap<Iterator, Function>(i, f);
}
This is just a basic example and is still incomplete as it has no way to check if you've reached the end of the iterable sequence.
Here's a recreation of your example python code (also defining a simple infinite counter class).
#include <iostream>
class Counter
{
public:
Counter (int start) : value(start) {}
int operator* () { return value; }
void operator++ () { ++value; }
private:
int value;
};
int main(int argc, char const *argv[])
{
Counter source(0);
auto pipe1 = makeLazyIterMap(source, [](int n) { return 2 * n; });
auto pipe2 = makeLazyIterMap(pipe1, [](int n) { return n + 1; });
auto sink = makeLazyIterMap(pipe2, [](int n) { return 3 * n; });
for (int i = 0; i < 10; ++i, ++sink)
{
std::cout << *sink << std::endl;
}
}
Apart from the class definitions (which are just reproducing what the python library functions do), the code is about as long as the python version.
I think the boost::rangex library is what you are looking for. It should work nicely with the new c++lambda syntax.
int pipe1(int val) {
return 2*val;
}
int pipe2(int val) {
return val+1;
}
int sink(int val) {
return val*3;
}
for(int i=0; i < SOME_MAX; ++i)
{
cout << sink(pipe2(pipe1(i))) << endl;
}
I know, it's not quite what you were expecting, but it certainly evaluates at the time you want it to, although not with an iterator iterface. A very related article is this:
Component programming in D
Edit 6/Nov/12:
An alternative, still sticking to bare C++, is to use function pointers and construct your own piping for the above functions (vector of function pointers from SO q: How can I store function pointer in vector?):
typedef std::vector<int (*)(int)> funcVec;
int runPipe(funcVec funcs, int sinkVal) {
int running = sinkVal;
for(funcVec::iterator it = funcs.begin(); it != funcs.end(); ++it) {
running = (*(*it))(running); // not sure of the braces and asterisks here
}
return running;
}
This is intended to run through all the functions in a vector of such and return the resulting value. Then you can:
funcVec funcs;
funcs.pushback(&pipe1);
funcs.pushback(&pipe2);
funcs.pushback(&sink);
for(int i=0; i < SOME_MAX; ++i)
{
cout << runPipe(funcs, i) << endl;
}
Of course you could also construct a wrapper for that via a struct (I would use a closure if C++ did them...):
struct pipeWork {
funcVec funcs;
int run(int i);
};
int pipeWork::run(int i) {
//... guts as runPipe, or keep it separate and call:
return runPipe(funcs, i);
}
// later...
pipeWork kitchen;
kitchen.funcs = someFuncs;
int (*foo) = &kitchen.run();
cout << foo(5) << endl;
Or something like that. Caveat: No idea what this will do if the pointers are passed between threads.
Extra caveat: If you want to do this with varying function interfaces, you will end up having to have a load of void *(void *)(void *) functions so that they can take whatever and emit whatever, or lots of templating to fix the kind of pipe you have. I suppose ideally you'd construct different kinds of pipe for different interfaces between functions, so that a | b | c works even when they are passing different types between them. But I'm going to guess that that's largely what the Boost stuff is doing.
Depending on the simplicity of the functions :
#define pipe1(x) 2*x
#define pipe2(x) pipe1(x)+1
#define sink(x) pipe2(x)*3
int j = 1
while( ++j > 0 )
{
std::cout << sink(j) << std::endl;
}
The following code compiles and runs in Code::Blocks, but issues and error in VS2010:
"Undhandled exception at 0x770815de in test2.exe: 0xC0000005: Access violation writing to location 0x00000002."
I realise the code is sort of dangerous, it's basically prototyping an idea I have for another project. What I want to be able to do is pass a reference to any given number of ints followed by a value. Then put this value into the referenced ints and bob's your uncle. And it works, which is nice. But not in VS2010 which bothers me. I'm not the most experience with pointers, so I don't know if I'm doing something wrong or it's just this kind of operation is not something that VS2010 is fond of. Which is a problem because the project I'm testing this for is all in VS2010! So I need this to work for that!
EDIT: I'm sorry, I'm new to the Code:Blocks thing. I guess I should specify which compiler I use in Code::Blocks? :D I use the miniGW (or something) implementation of the GNU GCC Compiler (or something like that). I hope it makes sense to you experience Code::Blocks users!
#include <iostream>
#include <stdarg.h>
using namespace std;
void getMonkey(int Count, ... )
{
int test;
va_list Monkeys;
va_start(Monkeys, Count );
for(int i = 0; i < (Count / 2); i++ )
{
*va_arg(Monkeys, int*) = va_arg(Monkeys, int);
}
va_end(Monkeys);
}
int main()
{
int monkey1 = 0;
int monkey2 = 0;
int monkey3 = 0;
getMonkey(6, &monkey1, 2, &monkey2, 4, &monkey3, 5);
cout << monkey1 << " " << monkey2 << " " << monkey3;
return 0;
}
Turns out lvalues and rvalues are NOT evaluated in the order I assumed! TY stackoverflow!
Updated getMonkey method:
void getMonkey(int Count, ... )
{
int test;
va_list Monkeys;
va_start(Monkeys, Count );
for(int i = 0; i < (Count / 2); i++ )
{
int* tempMonkeyPtr = va_arg(Monkeys, int*); //herp
*tempMonkeyPtr = va_arg(Monkeys, int); //derp
}
va_end(Monkeys);
}
Yey! I'm getting a hang of this pointer business me thinks!
Background: I'm trying to figure out how to implement continuations/coroutines/generators (whatever the following is called) by posing this toy problem. The environment is C++11 on gcc 4.6 and linux 3.0 x86_64. Non-portable is fine but using an external library (boost.coroutine, COROUTINE, etc) is not allowed. I think longjmp(3) and/or makecontext(2) and friends may help but not sure.
Description:
The following toy parser is supposed to parse sequences of as and bs of equal length. ie
((a+)(b+))+
such that the length of the second bracketed production equals the third.
When it finds a production (eg aaabbb) it outputs the number of as it finds (eg 3).
Code:
#include <stdlib.h>
#include <iostream>
using namespace std;
const char* s;
void yield()
{
// TODO: no data, return from produce
abort();
}
void advance()
{
s++;
if (*s == 0)
yield();
}
void consume()
{
while (true)
{
int i = 0;
while (*s == 'a')
{
i++;
advance();
}
cout << i << " ";
while (i-- > 0)
{
if (*s != 'b')
abort();
advance();
}
}
}
void produce(const char* s_)
{
s = s_;
// TODO: data available, continue into consume()
consume();
}
int main()
{
produce("aaab");
produce("bba");
produce("baa");
produce("aabbb");
produce("b");
// should print: 3 1 4
return 0;
}
Problem:
As you can see the state of the consume call stack must be saved when yield is called and then produce returns. When produce is called again, consume must be restarted by returning from yield. The challenge would be to modify the way produce calls consume, and implement yield so they function as intended.
(Obviously reimplementing consume so that it saves and rebuilds its state defeats the purpose of the exercise.)
I think what needs to be done is something like the example on the bottom of the makecontext man page: http://www.kernel.org/doc/man-pages/online/pages/man3/makecontext.3.html, but its not clear how to translate it onto this problem. (and I need sleep)
Solution:
(Thanks to Chris Dodd for design)
#include <stdlib.h>
#include <iostream>
#include <ucontext.h>
using namespace std;
const char* s;
ucontext_t main_context, consume_context;
void yield()
{
swapcontext(&consume_context, &main_context);
}
void advance()
{
s++;
if (*s == 0)
yield();
}
void consume()
{
while (true)
{
int i = 0;
while (*s == 'a')
{
i++;
advance();
}
cout << i << " ";
while (i-- > 0)
{
advance();
}
}
}
void produce(const char* s_)
{
s = s_;
swapcontext(&main_context, &consume_context);
}
int main()
{
char consume_stack[4096];
getcontext(&consume_context);
consume_context.uc_stack.ss_sp = consume_stack;
consume_context.uc_stack.ss_size = sizeof(consume_stack);
makecontext(&consume_context, consume, 0);
produce("aaab");
produce("bba");
produce("baa");
produce("aabbb");
produce("b");
// should print: 3 1 4
return 0;
}
Its fairly straight-forward to use makecontext/swapcontext for this -- you use makecontext to create a new coroutine context and swapcontext to swap between them. In you case, you need one additional coroutine to run the consume infinite loop, and you run main and produce in the main context.
So main should call getcontext+makecontext to create a new context that will run the consume loop:
getcontext(&consume_ctxt);
// set up stack in consume_context
makecontext(&consume_ctxt, consume, 0);
and then produce will switch to it instead of calling consume directly:
void produce(const char* s_)
{
s = s_;
swapcontext(&main_ctxt, &consume_ctxt);
}
and finally yield just calls swapcontext(&consume_ctxt, &main_ctxt); to switch back to the main context (which will continue in produce and immediately return).
Note that since consume is an infinite loop, you don't need to worry too much about what happens when it returns (so the link will never be used)
I am trying to write a logger class for my C++ calculator, but I'm experiencing a problem while trying to push a string into a list.
I have tried researching this issue and have found some information on this, but nothing that seems to help with my problem. I am using a rather basic C++ compiler, with little debugging utilities and I've not used C++ in quite some time (even then it was only a small amount).
My code:
#ifndef _LOGGER_H_
#define _LOGGER_H_
#include <iostream>
#include <list>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::list;
using std::string;
class Logger
{
private:
list<string> mEntries;
public:
Logger() {}
~Logger() {}
// Public Methods
void WriteEntry(const string& entry)
{
mEntries.push_back(entry);
}
void DisplayEntries()
{
cout << endl << "**********************" << endl
<< "* Logger Entries *" << endl
<< "**********************" << endl
<< endl;
for(list<string>::iterator it = mEntries.begin();
it != mEntries.end(); it++)
{
// *** BELOW LINE IS MARKED WITH THE ERROR ***
cout << *it << endl;
}
}
};
#endif
I am calling the WriteEntry method by simply passing in a string, like so:
mLogger->WriteEntry("Testing");
Any advice on this would be greatly appreciated.
* CODE ABOVE HAS BEEN ALTERED TO HOW IT IS NOW *
Now, the line:
cout << *it << endl;
causes the same error. I'm assuming this has something to do with how I am trying to get the string value from the iterator.
The code I am using to call it is in my main.cpp file:
#include <iostream>
#include <string>
#include <sstream>
#include "CommandParser.h"
#include "CommandManager.h"
#include "Exceptions.h"
#include "Logger.h"
using std::string;
using std::stringstream;
using std::cout;
using std::cin;
using std::endl;
#define MSG_QUIT 2384321
#define SHOW_LOGGER true
void RegisterCommands(void);
void UnregisterCommands(void);
int ApplicationLoop(void);
void CheckForLoggingOutput(void);
void ShowDebugLog(void);
// Operations
double Operation_Add(double* params);
double Operation_Subtract(double* params);
double Operation_Multiply(double* params);
double Operation_Divide(double* params);
// Variable
CommandManager *mCommandManager;
CommandParser *mCommandParser;
Logger *mLogger;
int main(int argc, const char **argv)
{
mLogger->WriteEntry("Registering commands...\0");
// Make sure we register all commands first
RegisterCommands();
mLogger->WriteEntry("Command registration complete.\0");
// Check the input to see if we're using the program standalone,
// or not
if(argc == 0)
{
mLogger->WriteEntry("Starting application message pump...\0");
// Full version
int result;
do
{
result = ApplicationLoop();
} while(result != MSG_QUIT);
}
else
{
mLogger->WriteEntry("Starting standalone application...\0");
// Standalone - single use
// Join the args into a string
stringstream joinedStrings(argv[0]);
for(int i = 1; i < argc; i++)
{
joinedStrings << argv[i];
}
mLogger->WriteEntry("Parsing argument '" + joinedStrings.str() + "'...\0");
// Parse the string
mCommandParser->Parse(joinedStrings.str());
// Get the command names from the parser
list<string> commandNames = mCommandParser->GetCommandNames();
// Check that all of the commands have been registered
for(list<string>::iterator it = commandNames.begin();
it != commandNames.end(); it++)
{
mLogger->WriteEntry("Checking command '" + *it + "' is registered...\0");
if(!mCommandManager->IsCommandRegistered(*it))
{
// TODO: Throw exception
mLogger->WriteEntry("Command '" + *it + "' has not been registered.\0");
}
}
// Get each command from the parser and use it's values
// to invoke the relevant command from the manager
double results[commandNames.size()];
int currentResultIndex = 0;
for(list<string>::iterator name_iterator = commandNames.begin();
name_iterator != commandNames.end(); name_iterator++)
{
string paramString = mCommandParser->GetCommandValue(*name_iterator);
list<string> paramStringArray = StringHelper::Split(paramString, ' ');
double params[paramStringArray.size()];
int index = 0;
for(list<string>::iterator param_iterator = paramStringArray.begin();
param_iterator != paramStringArray.end(); param_iterator++)
{
// Parse the current string to a double value
params[index++] = atof(param_iterator->c_str());
}
mLogger->WriteEntry("Invoking command '" + *name_iterator + "'...\0");
results[currentResultIndex++] =
mCommandManager->InvokeCommand(*name_iterator, params);
}
// Output all results
for(int i = 0; i < commandNames.size(); i++)
{
cout << "Result[" << i << "]: " << results[i] << endl;
}
}
mLogger->WriteEntry("Unregistering commands...\0");
// Make sure we clear up our resources
UnregisterCommands();
mLogger->WriteEntry("Command unregistration complete.\0");
if(SHOW_LOGGER)
{
CheckForLoggingOutput();
}
system("PAUSE");
return 0;
}
void RegisterCommands()
{
mCommandManager = new CommandManager();
mCommandParser = new CommandParser();
mLogger = new Logger();
// Known commands
mCommandManager->RegisterCommand("add", &Operation_Add);
mCommandManager->RegisterCommand("sub", &Operation_Subtract);
mCommandManager->RegisterCommand("mul", &Operation_Multiply);
mCommandManager->RegisterCommand("div", &Operation_Divide);
}
void UnregisterCommands()
{
// Unregister each command
mCommandManager->UnregisterCommand("add");
mCommandManager->UnregisterCommand("sub");
mCommandManager->UnregisterCommand("mul");
mCommandManager->UnregisterCommand("div");
// Delete the logger pointer
delete mLogger;
// Delete the command manager pointer
delete mCommandManager;
// Delete the command parser pointer
delete mCommandParser;
}
int ApplicationLoop()
{
return MSG_QUIT;
}
void CheckForLoggingOutput()
{
char answer = 'n';
cout << endl << "Do you wish to view the debug log? [y/n]: ";
cin >> answer;
switch(answer)
{
case 'y':
ShowDebugLog();
break;
}
}
void ShowDebugLog()
{
mLogger->DisplayEntries();
}
// Operation Definitions
double Operation_Add(double* values)
{
double accumulator = 0.0;
// Iterate over all values and accumulate them
for(int i = 0; i < (sizeof values) - 1; i++)
{
accumulator += values[i];
}
// Return the result of the calculation
return accumulator;
}
double Operation_Subtract(double* values)
{
double accumulator = 0.0;
// Iterate over all values and negativel accumulate them
for(int i = 0; i < (sizeof values) - 1; i++)
{
accumulator -= values[i];
}
// Return the result of the calculation
return accumulator;
}
double Operation_Multiply(double* values)
{
double accumulator = 0.0;
for(int i = 0; i < (sizeof values) - 1; i++)
{
accumulator *= values[i];
}
// Return the value of the calculation
return accumulator;
}
double Operation_Divide(double* values)
{
double accumulator = 0.0;
for(int i = 0; i < (sizeof values) - 1; i++)
{
accumulator /= values[i];
}
// Return the result of the calculation
return accumulator;
}
Did you remember to call mLogger = new Logger at some point? Did you accidantally delete mLogger before writing to it?
Try running your program in valgrind to see whether it finds any memory errors.
After your edit, the solution seem clear:
Your first line in main() is :
mLogger->WriteEntry("Registering commands...\0");
Here mLogger is a pointer that has never been initialized. This is "undefined behaviour", meaning anything can appen, often bad things.
To fix this you can either make it a "normal" variable, not a pointer or create a Logger instance using new (either at the declaration or as the first line in main).
I suggest you to not use a pointer to be sure the logger is always there and is automatically destroyed.
By the way, it seems like you want to create every instance of objects on the heap using pointers. It's not recommanded if it's not necessary. You should use pointers ONLY if you want to explicitely state the creation (using new) and destruction (using delete) of the instance object. If you just need it in a specific scope, don't use a pointer. You might come from another language like Java or C# where all objects are referenced. If so, you should start learning C++ like a different language to avoid such kind of problem. You should learn about RAII and other C++ scpecific paradigm that you cannot learn in those languages. If you come from C you should too take it as a different language. That might help you avoid complex problems like the one you showed here. May I suggest you read some C++ pointer, references and RAII related questions on stackoverflow.
First, you don't need to create the std::list on the heap. You should just use it as a normal member of the class.
class Logger
{
private:
list<string> mEntries; // no need to use a pointer
public:
Logger() // initialization is automatic, no need to do anything
{
}
~Logger() // clearing and destruction is automatic too, no need to do anything
{
}
//...
};
Next, entryData don't exist in this code so I guess you wanted to use entry. If it's not a typo then you're not providing the definition of entryData that is certainly the source of your problem.
In fact I would have written your class that way instead:
class Logger
{
private:
list<string> mEntries;
public:
// no need for constructor and destructor, use the default ones
// Public Methods
void WriteEntry(const string& entry) // use a const reference to avoid unnecessary copy (even with optimization like NRVO)
{
mEntries.push_back( entry ); // here the list will create a node with a string inside, so this is exactly like calling the copy constructor
}
void DisplayEntries()
{
cout << endl << "**********************" << endl
<< "* Logger Entries *" << endl
<< "**********************" << endl
<< endl;
for(list<string>::iterator it = mEntries.begin();
it != mEntries.end(); ++it) // if you want to avoid unnecessary copies, use ++it instead of it++
{
cout << *it << endl;
}
}
};
What's certain is that your segfault is from usage outside of this class.
Is an instance of Logger being copied anywhere (either through a copy constructor or operator=)? Since you have mEntries as a pointer to a list, if you copy an instance of Logger, they will share the value of the pointer, and when one is destructed, it deletes the list. The original then has a dangling pointer. A quick check is to make the copy constructor and operator= private and not implemented:
private:
void operator=(const Logger &); // not implemented
Logger(const Logger &); // not implemented
When you recompile, the compiler will flag any copies of any Logger instances.
If you need to copy instances of Logger, the fix is to follow the Rule of 3:
http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29
You can do this by eliminating the need for the destructor (by not using a pointer: list<string> mEntries), or by adding the needed code to the copy constructor and operator= to make a deep copy of the list.
You only need to do
list<string> entries;
entries.push_back();
You do not need to create a pointer to entries.
Nothing too obvious, though you typed
mEntries->push_back(string(entryData));
and I htink you meant entry instead of entryData. You also don't need the string conversion on that line, and your function should take entry by const reference.
However, none of these things would cause your program to segfault. What compiler are you using?
You're missing the copy constructor. If the Logger object is copied and the original deleted, you'll be dereferencing memory that was previously deleted.
A simplified example of the problem
Logger a;
{
Logger b;
a=b;
}
a.WriteEntry("Testing");
Add a copy constructor.
Logger(const Logger& item)
{
mEntries = new list<string>();
std::copy(item.mEntries->begin(), item.mEntries->end(), std::back_inserter(*mEntries));
}