Storing objects in multiple lists of shared_ptr - c++

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?

Related

EXC_BAD_ACCESS only when building object inside function

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.

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

Pattern State in C++

I am trying to implement the Pattern State in C++.
I have my client: Player
State as the interface
and the 2 State: In and Out
This is my In.h:
#ifndef ODA_IN_H
#define ODA_IN_H
#include <vector>
#include "Player.h"
#include "Hand.h"
using namespace std;
class In : public State {
public:
In(Player* player);
void doYouChange();
Card throwCard(int i);
void showHand();
void setHand(vector<Card> &other);
private:
Player* player;
Hand hand;
};
#endif
And the In.cpp:
#include <iostream>
#include "In.h"
using namespace std;
In::In(Player* player) {
this->player = player;
cout << player->getName() <<endl;
}
void In::doYouChange() {
string sth;
do {
cout << player->getName() << ", Do you want to leave for this round?(Yes/No)?";
cin >> sth;
} while (sth != "No" && sth != "Yes");
if (sth == "Yes") {
player->setState(player->getOut());
}
}
Card In::throwCard(int i) {
Card c = hand.getCard(i);
return c;
}
void In::showHand() {
hand.showHand();
}
void In::setHand(vector<Card> &other) {
hand.setHand(other);
}
So the constructor can write out the name, while the doYouChange() method no. And later it breaks totally no message just memory junk:/
I call the doYouChange() from an other class like this:
for (int i = 0; i < playersNb; ++i) {
players[i].doYouChange();
}
The first player okay without name, the on the second it breaks.
I have absolutely no idea. I tried to reimplement and everything but nothing helped.
/****************/
UPDATE:
Creating one Player (as a Client of Pattern State in the constructor I initialize also the states):
Player::Player(string n) {
name = n;
out = new Out(this);
in = new In(this);
this -> state = in;
}
And in the same class with the for I add players in the constructor:
players.push_back(Player(name));
This error will very likely occure due to the fact that player becomes invalid (/destroyed).
Consider the following code:
Player* player = new Player();
In inState(player); // will work
inState->doYouChange(); // will work
delete player;
inState->doYouChange(); // wont work
Without more details we cant give you a concrete solution but just general advices:
Make sure that you know who manages your player objects
Check the cases where these objects become destroyed, try to breakpoint them, do your player objects really become destroyed?
Breakpoint the doYouChange() method and check the player object
Consider using smart pointers to overcome an ownership problem: See std::shared_ptr (there are also many other libraries out there which might provide smart pointers better suiting your needs, e.g Poco or Boost)

How do I point at a vector in another class?

I have a class that holds a vector, which also inherits another class:
class txtExt : public extention
{
private:
string openedFile_;
public:
vector<string> txtVector; //the vector i want to call
};
I fill the vector in a method within a class:
class Manager : public extention
{
// there is some other code here that I know does work
// and it calls this function:
void organizeExtention(string filename, string ext)
{
if(ext == "txt")
{
txtExt txtExt;
txtExt.txtVector.pushback(filename);
}
}
}
and this is my main class where i attempt to call the vector:
int main()
{
// some code here that does previous operations like getting the path
// and filling the vector
// I've tried many ways of trying to call the vector
// here is an example of one:
vector<txtExt*> testVector;
for(int i = 0; i < testVector.size(); ++i)
{
cout << testVector[i] << endl;
}
return 0;
}
I have a few questions:
Am I calling the vector wrong?
Is my vector empty?
Do I have to make my vector global, so other classes can see it?
Note: I've been able to print out the vector where I load the vector using a very simple for loop
Well, as has been said you have a few errors in the code posted, and you maybe have some misunderstandings as well. But to answer the question asked, this
testVector[i]->txtVector
is the way to access the txtVector object that is inside each of your txtExt objects.
If that doesn't work for you then it's because one of the other errors/misunderstandings you have in your code.
To summarize:
reread the first chapters of a good C++ book ( The Definitive C++ Book Guide and List ), then try try to fix your program and deal with each error one at the time.
There are several errors in your code.
First of all, there's no operator << for printing entities of the type txtExt*.
Even object of type txtExt is not printable just like that.
In addition, the testVector you made is empty, so no .size() will be zero, and there's going to be no looping.
Are you really sure that you like to inherit both your classes from 'extension' ?
You can't call a vector, you can access it.
Having a data member (like the vector) public is not a good idea.
Calling a variable by the same name as a class is a very bad idea.
I have trouble guessing what your code should do. Here's a simple example of things you need to understand:
#include <iostream>
#include <vector>
#include <string>
class TxtExt
{
public:
std::vector<std::string> txtVector;
};
int main(){
TxtExt oneTxtExt;
oneTxtExt.txtVector.push_back("hello");
oneTxtExt.txtVector.push_back("world");
for( auto &i : oneTxtExt.txtVector ){
std::cout << i <<std::endl;
}
}
The following code is correct, but has absolutely no effect. You could as well just write {}:
{
TxtExt TxtExt;
TxtExt.txtVector.pushback(filename);
}
You here create a new object, push back to it (btw it is called push_back), but then the object is destroyed at the end of the scope. Also, don't name you objects the same as the class, it becomes really confusing.