EXC_BAD_ACCESS only when building object inside function - c++

I'm working on a C++ project in XCode and I'm getting what appears to be some strange behavior (based on how I understand it). Here's my code:
#include <iostream>
#include <vector>
#include <string>
class beep {
public:
virtual void greet() {
std::cout << "bleep\n";
}
};
class boop : public beep {
public:
void greet() {
std::cout << "bloop\n";
}
};
class beep_master {
public:
std::vector<beep*> beeps;
void beep_everything() {
for (int i = 0; i < beeps.size(); i++) {
beeps[i]->greet();
}
}
};
beep_master factory() {
boop boop1;
boop boop2;
beep_master master;
master.beeps.push_back(&boop1);
master.beeps.push_back(&boop2);
return master;
}
int main(int argc, const char * argv[]) {
beep_master master = factory();
beep_master* ref = &master;
ref->beep_everything();
return 0;
}
I'm running this via XCode, and I'm getting an EXC_BAD_ACCESS in the for-loop in beep_master. Everywhere I've looked on the internet seems to indicate this is due to some memory management issues but I'm not really allocating anything dynamically.
I've noticed that if I move the contents of factory into main that I no longer get the error which leads me to believe it has something to do with boop1 and boop2 going out of scope and making the pointers invalid after the code exits that function.
Noodling on this, I'm beginning to think that this issue is unavoidable without the use of dynamic memory via the new operator and shared_ptr. Is this the right direction, or am I missing something in my setup here?

You are right. The factory function is storing pointers to local variables boop1 and boop2 which go away when the function returns, so you're left with pointers that point to invalid data.
You're pretty much going to have to dynamically allocate your objects to store the pointers in your vector.

Related

Storing objects in multiple lists of shared_ptr

I am working on a simple game for which i need to store the game-objects in containers. I want to store them in different std::list (objects that get drawn to the screen every frame, objects that need to be updated every frame, etc) so i can just iterate over all objects of a certain type when i need it. Now some objects have to be in more than one list (some of them get drawn and need to be updated every frame) and sometimes it is necessary to delete one from all lists that contain it. The objects should get deleted when they are removed from all lists. This is a simplified example of what i currently have:
#include <iostream>
#include <memory>
#include <string>
#include <list>
class A
{
public:
A(std::string text)
{
message = text;
}
~A()
{
std::cout << "Deleted: " << message << std::endl;
}
std::string getMessage() { return message; }
private:
std::string message;
};
int main()
{
std::list<std::shared_ptr<A>> list1;
std::list<std::shared_ptr<A>> list2;
if(true) // to create scope
{
std::shared_ptr<A> tmp(new A("Test"));
list1.push_back(std::shared_ptr<A>(tmp));
list2.push_back(std::shared_ptr<A>(tmp));
} // tmp out of scope
// delete the object from both lists:
auto i = std::begin(list1);
while(i != std::end(list1))
{
if(i->get()->getMessage() == "Test");
list1.remove(*i);
list2.remove(*i); // the object gets deleted after this line
}
return 0;
}
It work's but it really seems overly complicated (i'm using C# at work where this task is trivial). I have very little experience with memory management using smart pointers. Am i doing something fundamentally wrong?

Why does my class std::vector member always throw a segfault?

I've searched endlessly on SE for a logical explanation for why this is happening. It is probably something very simple that I've overlooked, however I cannot spot it and would really appreciate some assistance with this.
Last week I implemented a class to read the output of a system call from a .ini file and then find and store the required information into custom objects that are then stored in a vector inside a Config class. It is a Singleton config class storing a unique_ptr for each instance of my custom class that is created.
The thing is, when I implemented this last week on my laptop, I had zero issues reading and writing to my member vector and was able to get it working exactly how I needed it. Since pulling to my desktop computer, this vector, and any STL container that I use as a member of my class, throws a segmentation fault when I try to do anything on it, even get it's size.
I've tried to shorten the code below to only include sections that actually use this vector. I have replaced my config with A, and custom class with T, and no matter where I try to use my member container, or any other test STL containers that I add to the class, I get a segfault.
For the record, I am using Qt with C++11.
Update: This example breaks on line 50 of c.cpp when debugging, and anywhere that tries to call the vector.
Debug points to this line in stl_vector.h
// [23.2.4.2] capacity
/** Returns the number of elements in the %vector. */
size_type
size() const _GLIBCXX_NOEXCEPT
/*-> this line */ { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
main.cpp
#include "c.h"
int main(int argc, char *argv[])
{
C *c = C::getInstance();
delete c;
return 0;
}
t.h - Class stores information from file
#include <string>
class T
{
public:
T();
bool Active();
std::string getA();
void setA(std::string);
private:
std::string a;
};
t.cpp
#include "t.h"
T::T()
{
}
bool T::Active()
{
if(a == "")
{
return false;
}
return true;
}
std::string T::getA()
{
return this->a;
}
void T::setA(std::string newa)
{
this->a = newa;
}
c.h - Class stores T objects and parses file for information
#include "t.h"
#include <QDebug>
#include <vector>
#include <algorithm>
#include <iostream>
#include <memory>
#include <sstream>
#include <fstream>
class C
{
public:
static C* getInstance();
private:
C();
static C* instance;
static bool init;
std::vector<std::unique_ptr<T>> t_list;
void readLines(const std::string&);
};
c.cpp
#include "c.h"
bool C::init = false;
C* C::instance = nullptr;
C::C()
{
system("echo this is a test command > a.ini");
instance->readLines("a.ini");
}
C* C::getInstance()
{
if(!init)
{
instance = new C;
init = true;
}
return instance;
}
void C::readLines(const std::string &path)
{
T* new_t;
std::ifstream file(path.c_str());
if(!file.is_open())
{
qDebug() << "Unable to open " << path.c_str();
}
std::ofstream o("test.txt");
std::string line;
while(std::getline(file, line))
{
// Split string before searching
std::stringstream ss(line);
std::string seg;
std::vector<std::string> split;
std::string left, right;
// Search patterns
size_t find_a = line.find("a");
size_t del = line.find(':');
if(find_a != std::string::npos)
{
o << "test_Size: " << t_list.size() << std::endl;
if(new_t->Active())
{
T* temp = new_t;
std::unique_ptr<T> move_t(temp);
t_list.push_back(std::move(move_t));
}
o << "test: " << t_list.size() << std::endl;
std::string n;
// Check if previous ahas any null elements
// Split string to find a
n = line.substr(line.find("a "));
n = n.substr(n.find(" ", +2));
new_t->setA(n);
}
else
{
continue;
}
}
// Add last a
T* t = new_t;
std::unique_ptr<T> move_t(t);
//t_list.push_back(std::move(move_t));
o << "a: " << t_list.back().get()->getA() << std::endl;
o << t_list.size() << std::endl;
o.close();
file.close();
}
UPDATE after code change:
I see two things now: One is that new_t in C::readlines is never initialized, so this could break when new_t->Active() is called a bit later in the function. However, I believe that the main problem you're running into is in C::C(), where it says
instance->readLines("a.ini");
At this point in the execution, C::instance is not yet initialized -- you're only just constructing the object that would later be assigned to it. Because of this, this in the readlines call is invalid, and any attempt to access object members will cause UB. This latter problem can be fixed by just calling
readLines("a.ini");
in which case the currently constructed object (that will later be instance) is used for this. I have no idea what you want to happen for the first, though, so all I can say is: If you want to have a vector<unique_ptr<T>>, you will have to create objects of type T with either new T() or (arguably preferrably) std::make_unique<T>() and put them in there.
I'll also say that this is a rather ugly way to implement a singleton in C++. I mean, singletons are never really pretty, but if you're going to do it in C++, the usual way is something like the accepted answer of C++ Singleton design pattern .
Old answer:
The problem (if it is the only one, which I cannot verify because you didn't provide an MCVE) is in the lines
T move_t = new_T;
std::unique_ptr<Adapter> ptr_t(&move_t); // <-- particularly this one
m_ts.push_back(std::move(ptr_t));
You're passing a pointer to a local object into a std::unique_ptr, but the whole purpose of std::unique_ptr is to handle objects allocated with new to avoid memory leaks. Not only will the pointer you pass into it be invalid once the scope surrounding this declaration is left, even if that weren't the case the unique_ptr would attempt to delete an object that's not on the heap at the end of its lifecycle. Both problems cause undefined behavior.
To me, it looks as though you really want to use a std::vector<T> instead of std::vector<std::unique_ptr<T>>, but that's a design issue you'll have to answer yourself.
Answering my own question here. I am trying to call a member variable from within the constructor of the object that holds it, so the vector I am trying to access is not yet instantiated and doesn't exist in memory. That is what causes the Segmentation fault to occur, I am trying to access memory that is not allocated yet, hence any call acting on any member of my C class was causing this issue.
I fixed this problem by adding a public function to the class that then calls the private readLines() function. I call that public function from the object that will take ownership of it, and since this occurs after it has been instantiated, the memory is accessible and the problem disappears.

will the shared_ptr be deleted if i delete the class

I have a class like this :
Header:
class CurlAsio {
public:
boost::shared_ptr<boost::asio::io_service> io_ptr;
boost::shared_ptr<curl::multi> multi_ptr;
CurlAsio();
virtual ~CurlAsio();
void deleteSelf();
void someEvent();
};
Cpp:
CurlAsio::CurlAsio(int i) {
id = boost::lexical_cast<std::string>(i);
io_ptr = boost::shared_ptr<boost::asio::io_service>(new boost::asio::io_service());
multi_ptr = boost::shared_ptr<curl::multi>(new curl::multi(*io_ptr));
}
CurlAsio::~CurlAsio() {
}
void CurlAsio::someEvent() {
deleteSelf();
}
void CurlAsio::deleteSelf() {
if (io_ptr) {
io_ptr.reset();
}
if (multi_ptr)
multi_ptr.reset();
if (this)
delete this;
}
During run time, many instances of CurlAsio Class is created and deleted.
So my questions are:
even though I am calling shared_ptr.reset() , is it necessary to do so ?
i monitor the virtual memory usage of the program during run time and I would expect the memory usage would go down after deleteSelf() has been called, but it does not. Why is that?
if i modify the deleteSelf() like this:
void CurlAsio::deleteSelf() {
delete this;
}
What happens to the two shared pointers ? do they get deleted as well ?
The shared_ptr members have their own destructor to decrement the reference count on the pointee object, and delete it if the count reaches 0. You do not need to call .reset() explicitly given your destructor is about to run anyway.
That said - why are you even using a shared_ptr? Are those members really shared with other objects? If not - consider unique_ptr or storing by value.
As for memory - it doesn't normally get returned to the operating system until your program terminates, but will be available for your memory to reuse. There are many other stack overflow questions about this.
If you're concerned about memory, using a leak detection tool is a good idea. On Linux for example, valgrind is excellent.
if i modify the deleteSelf() like this:
void CurlAsio::deleteSelf() {
delete this;
}
Don't do this. This is an antipattern. If you find yourself "needing" this, shared_from_this is your solution:
Live On Coliru
#include <boost/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
#include <vector>
struct X : boost::enable_shared_from_this<X> {
int i = rand()%100;
using Ptr = boost::shared_ptr<X>;
void hold() {
_hold = shared_from_this();
}
void unhold() { _hold.reset(); }
~X() {
std::cout << "~X: " << i << "\n";
}
private:
Ptr _hold;
};
int main() {
X* raw_pointer = nullptr; // we abuse this for demo
{
auto some_x = boost::make_shared<X>();
// not lets addref from inside X:
some_x->hold();
// now we can release some_x without destroying the X pointed to:
raw_pointer = some_x.get(); // we'll use this to demo `unhold()`
some_x.reset(); // redundant since `some_x` is going out of scope here
}
// only the internal `_hold` still "keeps" the X
std::cout << "X on hold\n";
// releasing the last one
raw_pointer->unhold(); // now it's gone ("self-delete")
// now `raw_pointer` is dangling (invalid)
}
Prints e.g.
X on hold
~X: 83

Issue with struct constructor causing stack overflow

Both sections of code below are drastically simplified, isolated versions of my actual code. The examples are just big enough to reproduce the problem. The first section of code below works fine. The section section is an attempt to begin to make it part of a class. I'm trying to take tiny steps since small modifications to something like the struct shown below require lots of changes throughout the code which is full of pointers, pointer to pointers and references which all involve this struct. Can you tell me why the second section of code throws a stack overflow within it's constructor and what small changes can be made to fix it?
Working code:
#include <cstdio>
#include <cstdlib>
#include <iostream>
using std::cout;
using std::endl;
const int maxSize = 3;
struct Item{
int count;
Item *items[maxSize + 1];
};
void foo()
{
Item *p;
p = new Item();
p->count = 2;
cout << p->count << endl;
}
int main(int argc, char *argv[])
{
foo();
return 0;
}
Attempt to very gradually modify the code as a whole toward becoming a class:
#include <cstdio>
#include <cstdlib>
#include <iostream>
using std::cout;
using std::endl;
int maxSize = 3;
struct Item{
int count;
Item *items;
Item()
{
items = new Item[maxSize + 1]; // stack overflow
}
};
void Initialize(int size)
{
maxSize = size;
}
void foo()
{
Item *p;
p = new Item();
p->count = 2;
cout << p->count << endl;
}
int main(int argc, char *argv[])
{
Initialize(5);
foo();
return 0;
}
The first call to construct a Item calls new Item[maxSize+1], which calls the default constructor, which calls new Item[maxSize+1], which calls the default construct, and so on until you reach stack overflow.
All the answers are right. I want to suggest a solution for you:
Instead of initializing the array within the ctor, you could implement an initialization method like
init(int maxSize) {
items = new Item[maxSize + 1];
}
that you can call after having constructed the object. This should avoid the stack overflow. In general, you should avoid to place instances of an object inside the object itself. Its better to use Collections of the Item
List<Item>, std::vector<Item>, ...
It is because in working version you have reference to an array of object, but not actual object of Items. In second version, you are creating objects by using keyword new. So, in second version in constructor it will call itself! It will call it's own constructor infinite times. Hence, you see runtime exception stackoverflow :)
Above posters are right. Within the constructor of Item you create items (by creating an array). So the ctor is again called, which creates more items, which .... This is more or less an infinite loop which eats up your stack.
Either stick with the references or use a collection like List - so you can add the items later on dynamically.

C++ Syntax errors

I'm trying to make a kind of screen manager in C++ but I'm getting errors.
With my code below I receive
1>screenmanager.cpp(26): error C2664: 'void std::vector<_Ty>::push_back(_Ty &&)' : cannot convert parameter 1 from 'virtualGameScreen' to 'virtualGameScreen *&&'
1> with
1> [
1> _Ty=virtualGameScreen *
1> ]
1> Reason: cannot convert from 'virtualGameScreen' to 'virtualGameScreen *'
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>
Errors occur with gameScreen.push_back(gameScreenToAdd);
I get access violation error when adding a reference operator with gameScreenToAdd.
ScreenManager.h
void AddScreen(virtualGameScreen);
void RemoveScreen(virtualGameScreen);
ScreenManager.cpp
std::vector<virtualGameScreen*> gameScreen;
void ScreenManager::Initialize(void)
{
MainMenu menu = MainMenu();
AddScreen(menu);
}
void ScreenManager::AddScreen(virtualGameScreen gameScreenToAdd)
{
gameScreenToAdd.LoadContent();
gameScreen.push_back(gameScreenToAdd);
}
So, I've hit a bit of a wall, any suggestions on how I might fix this?
edit game runs if I change gameScreen.push_back to gameScreen.push_back(new MainMenu()); buut that's not really how I want the function to work
So, the first thing the compiler did is tell you where the problem occurs:
1>screenmanager.cpp(26)
It also told you primarily what the problem is:
Reason: cannot convert from 'virtualGameScreen' to 'virtualGameScreen *'
So - something in your code is providing a "virtualGameScreen" object instance where it was expecting a pointer (denoted by the *). And it's on line 26. The other parts of the error indicate it's the call to push_back. Lets look at line 26:
gameScreen.push_back(gameScreenToAdd);
Yep - you're calling push_back, and you're passing it gameScreenToAdd, which is of type virtualGameScreen. The push_back call is from this vector:
std::vector<virtualGameScreen*> gameScreen;
Your vector expects pointers, so the push_back expects vectors.
HOWEVER: You can't just do this:
gameScreen.push_back(&gameScreenToAdd);
because gameScreenToAdd is a temporary function variable - when you call AddScreen, the original variable is copied into a new, temporary virtualGameScreen for the lifetime of the function call. That means when the program leaves AddScreen the screen whose address you pushed will no-longer exist (the memory is still there, but it has been released and the computer will now proceed to use it for other reasons).
What you'll need to do is change AddScreen to take a pointer.
void ScreenManager::AddScreen(virtualGameScreen* gameScreenToAdd)
{
gameScreenToAdd.LoadContent();
gameScreen.push_back(gameScreenToAdd);
}
Unfortunately, this leaves you open to yet another problem with your code.
void ScreenManager::Initialize(void)
{
MainMenu menu = MainMenu();
AddScreen(menu);
}
This function creates a temporary, local MainMenu object - with a lifetime of the duration of Initialize. Then it creates a second, temporary MainMenu and copies it to menu.
If you write
AddScreen(&menu);
it will work, but it will pass the address of a temporary instance to AddScreen.
As soon as program flow leaves the "Initialize()" function, your value goes away.
It looks like you may have some prior experience with something like Java or C# and are trying to apply previous knowledge to C++.
What you need is a member variable to store "Menu" for the life time of the instance of ScreenManager.
Option 1: Just use a class member variable.
class ScreenManager
{
MainMenu m_menu;
public:
ScreenManager()
: m_menu() // initialize menu while we are initializing.
{}
void Initialize()
{
AddScreen(&m_menu);
}
// ...
};
If you really want to use a pointer, you might do the following:
class ScreenManager
{
MainMenu* m_menu;
public:
ScreenManager()
: m_menu(nullptr) // make sure it's null as soon as the object is created
{}
void Initialize()
{
m_menu = new MainMenu();
AddScreen(m_menu);
}
// but now we have to make sure it is released when we go away
~ScreenManager()
{
if (m_menu)
{
delete m_menu;
m_menu = nullptr;
}
}
};
Option 3: use C++ containers to manage the lifetime of the pointer for you, either std::unique_ptr or std::shared_ptr
---- EDIT ----
Seeing the edit you made while I was writing this, it's a little clearer what you're trying to do. What you probably want is something more like this:
std::vector<std::unique_ptr<virtualGameScreen>> gameScreen;
Consider the following:
Live demo: http://ideone.com/7Th2Uk
#include <iostream>
#include <vector>
class Foo {
const char* m_name;
public:
Foo(const char* name) : m_name(name) { std::cout << "Foo " << m_name << '\n'; }
~Foo() { std::cout << "~Foo " << m_name << '\n'; }
};
int main() {
std::vector<Foo*> foos;
Foo foo("foo");
foos.push_back(new Foo("new"));
return 0;
}
Note that the second foo is never released.
Foo foo
Foo new
~Foo foo
std::unique_ptr is a pointer-container object which will delete the object when the object expires. This makes it suitable for use in a container like std::vector
#include <iostream>
#include <vector>
#include <memory> // for std::unique_ptr
class Foo {
const char* m_name;
public:
Foo(const char* name) : m_name(name) { std::cout << "Foo " << m_name << '\n'; }
~Foo() { std::cout << "~Foo " << m_name << '\n'; }
};
int main() {
std::vector<std::unique_ptr<Foo>> foos;
Foo foo("foo");
foos.emplace_back(new Foo("new"));
return 0;
}
Both objects get cleaned up:
Foo foo
Foo new
~Foo foo
~Foo new
Now you don't need your m_menu at all, you can simply call AddScreen with a 'new MainMenu()' and the pointer will be added to the vector such that when the vector goes out of scope, proper cleanup will happen.
Menu* menu = new MainMenu();
AddScreen(menu);
or
AddScreen(new MainMenu());
In theory what you should really do is ensure that the allocation goes straight into a unique_ptr object so that there's no window for it to get leaked, but teaching the use of std::unique_ptr is beyond the scope of this answer. http://msdn.microsoft.com/en-us/library/hh279676.aspx, http://www.drdobbs.com/cpp/c11-uniqueptr/240002708, etc.
In pre-C++11 code, you might have something like this:
std::vector<virtualGameScreen*> gameScreen;
void ScreenManager::Initialize(void)
{
AddScreen(new MainMenu);
}
void ScreenManager::AddScreen(virtualGameScreen *gameScreenToAdd)
{
gameScreenToAdd->LoadContent();
gameScreen.push_back(gameScreenToAdd);
}
but you would have to have some way to make sure the object got deleted.
With C++11, you would probably want to have the memory managed automatically:
std::vector<std::unique_ptr<virtualGameScreen>> gameScreen;
void ScreenManager::Initialize(void)
{
AddScreen(std::unique_ptr<MainMenu>(new MainMenu));
}
void ScreenManager::AddScreen(std::unique_ptr<virtualGameScreen> gameScreenToAdd)
{
gameScreenToAdd->LoadContent();
gameScreen.emplace_back(std::move(gameScreenToAdd));
}
That's because you did not provide a pointer to the vector (gameScreen), and another issue about the code is that: the paramater will generate a temp object, if just put the address of it the app maybe crash.