std::bad_weak_ptr while shared_from_this - c++

To create my EventManager, I needed to create functions which would take shared_ptr of Listeners to store them into vectors and call their event function.
I did so, and it works correctly, unless when I close my program.
When closing it, the program crashes, saying "double free or corruption". I understood my problem came from my std::shared_ptr(this). So I tried to use shared_from_this... but it doesn't really seem to work.
main.cpp :
#include "Game.h"
#include "EventManager.h"
int main() {
EventManager evManager;
std::shared_ptr<Game> game(new Game(&evManager));
return 0;
}
Game.h & Game.cpp :
#ifndef GAME_H
#define GAME_H
#include "EventManager.h"
#include <memory>
class EventManager;
class Game : public std::enable_shared_from_this<Game>
{
public:
Game(EventManager* evManager);
};
#endif // GAME_H
#include "Game.h"
Game::Game(EventManager* evManager) {
evManager->addGame(shared_from_this());
}
EventManager.h & EventManager.cpp
#ifndef EVENTMANAGER_H
#define EVENTMANAGER_H
#include <memory>
#include "Game.h"
class Game;
class EventManager
{
public:
void addGame(std::shared_ptr<Game> game);
protected:
std::shared_ptr<Game> m_game;
};
#endif // EVENTMANAGER_H
#include "EventManager.h"
void EventManager::addGame(std::shared_ptr<Game> game) {
m_game = game;
}
I executed my program with hope it would work, but I got a std::bad_weak_ptr. This error seems to occur when you try to create a shared_ptr from something that no longer exists.
So I thought it could be that the program ended too fast for the shared_ptr to create. Unfortunately it's not the problem, I added a std::cout after the creation of the Game class and it never shows, the program crashes before.
I hope you understand my problem and can help me solve it,
Cheers.

http://en.cppreference.com/w/cpp/memory/enable_shared_from_this/shared_from_this
Notes
It is permitted to call shared_from_this only on a previously shared object, i.e. on an object managed by std::shared_ptr. Otherwise the behavior is undefined (until C++17)std::bad_weak_ptr is thrown (by the shared_ptr constructor from a default-constructed weak_this) (since C++17).
you call shared_from_this in constructor when there's no shared_ptr yet

Related

boost::multi_index_container crashes with _com_ptr_t objects

I try to use boost::multi_index_container with _com_ptr_t objects.
Code compiles with no warnings but crashes in runtime.
Standard containers (std::set, map etc) work perfectly with such objects.
Is it possible to use multi_index_container with _com_ptr_t?
Sample code here:
#include "stdafx.h"
#include <boost\multi_index_container.hpp>
#include <boost\multi_index\random_access_index.hpp>
#include <boost\multi_index\global_fun.hpp>
#include <boost\multi_index\ordered_index.hpp>
#import "C:\Windows\SysWOW64\msxml6.dll" exclude("ISequentialStream", "_FILETIME")
using CTest =
boost::multi_index_container<MSXML2::IXMLDOMDocument2Ptr,
boost::multi_index::indexed_by<boost::multi_index::random_access<>>>;
int main()
{
::CoInitialize(nullptr);
CTest tst;
MSXML2::IXMLDOMDocumentPtr doc;
doc.CreateInstance(CLSID_DOMDocument);
tst.push_back(std::move(doc)); <-- crash here
::CoUninitialize();
return 0;
}
I notice that the multi_index_container you've defined holds pointers of type MSXML2::IXMLDOMDocument2Ptr, yet doc is of type MSXML2::IXMLDOMDocumentPtr (without the 2). I'm assuming this is OK, as the problem is really not related to this discrepancy.
Boost.MultiIndex does support move semantics, so you can use std::move as you please.
The actual problem is that _com_ptr_t has a weird, destructive operator& overload returning a pointer to the wrapped interface. This confuses the internal code of Boost.MultiIndex. You can easily bypass this overload as follows:
#include <boost\multi_index_container.hpp>
#include <boost\multi_index\random_access_index.hpp>
#include <boost\multi_index\global_fun.hpp>
#include <boost\multi_index\ordered_index.hpp>
#import "C:\Windows\SysWOW64\msxml6.dll" exclude("ISequentialStream", "_FILETIME")
struct IXMLDOMDocument2Ptr:MSXML2::IXMLDOMDocument2Ptr
{
using MSXML2::IXMLDOMDocument2Ptr::IXMLDOMDocument2Ptr;
IXMLDOMDocument2Ptr* operator&(){return this;}
const IXMLDOMDocument2Ptr* operator&()const{return this;}
};
using CTest =
boost::multi_index_container<IXMLDOMDocument2Ptr,
boost::multi_index::indexed_by<boost::multi_index::random_access<>>>;
int main()
{
::CoInitialize(nullptr);
{
// defined in scope so that destruction happens before CoUninitialize
CTest tst;
MSXML2::IXMLDOMDocumentPtr doc;
doc.CreateInstance(CLSID_DOMDocument);
tst.push_back(std::move(doc));
}
::CoUninitialize();
return 0;
}
Would you mind entering a ticket for this problem at Boost Trac? I can fix the issue internally (by not relying on user-overloadable operator&s) but it's going to take a while till I find the time to do so and I wouldn't like to forget about it.
Postscript
If you have this problem throughout your program, you can automate the fix as follows:
#include <boost\multi_index_container.hpp>
#include <boost\multi_index\random_access_index.hpp>
#include <boost\multi_index\global_fun.hpp>
#include <boost\multi_index\ordered_index.hpp>
#import "C:\Windows\SysWOW64\msxml6.dll" exclude("ISequentialStream", "_FILETIME")
template<typename CComPtr>
struct CFixedAddressofComPtr:CComPtr
{
using CComPtr::CComPtr;
CFixedAddressofComPtr* operator&(){return this;}
const CFixedAddressofComPtr* operator&()const{return this;}
};
template<typename CComPtr,typename TIndexList>
using CComPtrMultiIndexContainer=boost::multi_index_container<
CFixedAddressofComPtr<CComPtr>,
TIndexList
>;
using CTest =
CComPtrMultiIndexContainer<MSXML2::IXMLDOMDocument2Ptr,
boost::multi_index::indexed_by<boost::multi_index::random_access<>>>;
int main()
{
::CoInitialize(nullptr);
{
// declared in scope so that destruction happens before CoUninitialize.
CTest tst;
MSXML2::IXMLDOMDocumentPtr doc;
doc.CreateInstance(CLSID_DOMDocument);
tst.push_back(std::move(doc));
}
::CoUninitialize();
return 0;
}

multithreading - Asynchronous threads in class

I've got a class Foo, which have a main function and execute function. I want to start an unknown number of threads with the execute function, but when I try to compile the code I always get error C2064: term does not evaluate to a function taking 1 arguments.
foo.h
#ifndef BOT_H
#define BOT_H
#pragma once
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <string>
class foo
{
public:
foo(char *_server, char *_port);
~foo(void);
private:
char *server;
char *port;
void execute(char *cmd);
void main();
};
#endif
foo.c
#include <thread>
#include "bot.h"
#include "definitions.h"
using namespace std;
foo::foo(char *_server, char *_port){
...
}
bot::~bot(void) {
...
}
void bot::execute(char *command){
...
}
void bot::main(){
thread(&bot::execute, (char*)commanda.c_str()).detach();
}
How should I create threads from class member functions?
Thanks for any answer
You need a bot object to call the member function on:
thread(&bot::execute, this, (char*)commanda.c_str())
^^^^
although you really should either change the function to take either std::string or const char*. You have a minefield of undefined behaviour here, if either the function tries to modify the string, or commanda is destroyed while the thread is still using it.
A lambda may be more readable; and would also fix the lifetime fiasco by capturing a copy of the string:
thread([=]{execute((char*)commanda.c_str();})

Class does not name a type error

I have the following code in a project:
#ifndef MAP_H
#define MAP_H
#include <string>
#include "MapCell.h"
using namespace std;
class Map{
public:
Map();
Map(int, int);
Map(string);
virtual ~Map();
private:
int grid_size;
MapCell * grid;
};
#endif
When I go to compile, I get the error "error: 'MapCell' does not name a type" yet when I comment out MapCell * grid and run this next block of code from main:
#include <iostream>
#include <cstdlib>
#include "MapCell.h"
using namespace std;
int main() {
MapCell * test_var;
test_var = new MapCell();
delete test_var;
cout << "Press enter to end process...";
cin.get();
cin.get();
return 0;
}
everything works just fine. I know my MapCell.h and .cpp files are in the right places and I'm guessing the compiler can see them since it works from main. I read around some other questions and most answers seem to point to either syntax errors or forward declarations which don't really fit here (unless I'm overlooking something)
Any ideas on what's going on here?
chris and greatwolf led me to the solution that fixed the problem. I needed to forward declare my MapCell class for the compiler to be able to link to the whole class.

C++ Classes dependent on each other causing a cyclic dependency error

My searches have lead me to believe that the problem I am experiencing is called cyclic redundancy. I don't understand any of the solutions that are posted. I am (fairly) new to C++, coming from a strong Java background.
Basically there are two classes that depend on each other. Class A contains a vector of class B objects, and class B contains methods that require class A objects as input.
Here's code that reproduces the problem.
According to codelite g++, the error is in school.h and is "person was not declared in this scope". It also says "template argument 1 is invalid" and "template argument number 2 is invalid". Then a couple of others, about non-class type "int" on all the vector functions that get invoked.
main.cpp
#include <iostream>
#include <string>
#include "person.h"
#include "school.h"
int main() {
person p;
school s;
std::cout << p.name << std::endl;
s.personVect.push_back(p);
std::cout << s.personVect.size() << std::endl;
std::cout << s.personVect.at(0).name << std::endl;
p.test();
return 0;
}
school.h
#ifndef SCHOOL_H
#define SCHOOL_H
#include <vector>
#include "person.h"
class school
{
public:
school();
~school();
std::vector<person> personVect;
};
#endif // SCHOOL_H
school.cpp
#include "school.h"
school::school(){}
school::~school(){}
person.h
#ifndef PERSON_H
#define PERSON_H
#include <string>
#include <vector>
#include "school.h"
class person {
public:
std::string name;
std::string phone;
school doSomethingWithSchool();
void test();
person();
~person();
};
#endif // PERSON_H
person.cpp
#include "person.h"
#include <iostream>
using namespace std;
person::person()
{
name = "marcus";
phone = "0400000000";
}
person::~person()
{
}
void person::test() {
cout << this->name;
}
school person::doSomethingWithSchool() {
school s;
}
The problem can be resolved by designing you class relationships better.
A Person isn't composed of a School, so it doesn't need to have a School member.
A School has a collection of Person objects.
If you want a person to do something with a school, pass it as an argument. This way you can use pointers and forward declarations to solve the issue.
// Person.h
class School; // Forward declare school type.
// Person.cpp
Person::DoSomethingWithSchool(School* school);
Your issue is with the fact that school.h has an #include "person.h" statement, and person.h has an #include "school.h" statement.
The solution
In the school class, instead of vector<person>, use vector<person*>. Instead of including person.h here, add the statement class person;. Assuming that your school class is eventually going to modify person objects somehow, put the #include person.h in your school.cpp file, after the statement #include school.h.
The error explained
This is a step-by-step breakdown of what happens when compiling:
In main.cpp, you first include person.h. The preprocessor goes and finds person.h. Since you've never included it before, PERSON_H has not yet been defined and the ifndef PERSON_H is currently true. So we go to the next line in the file.
The first interesting thing that happens in this file is that PERSON_H gets defined (#fdefine PERSON_H). The next time you #include this file, the preprocessor is going to skip the whole file, right to the #endif.
The second interesting thing to happen is that school.h gets included. So the preprocessor finds school.h (we haven't yet processed the School class!), which until now has never been processed.
The first interesting thing in school.h (after the #define SCHOOL_H) is the #include person.h, so the preprocessor returns to person.h (we haven't yet processed the Person class either!). But this time, PERSON_H is already defined, so #ifndef PERSON_H is false, and the preprocessor skips to the #endif in that file (as I mentioned in (2)). So the Person class still hasn't been declared.
We return to school.h, having done nothing. At this point, we are just about to declare/define the school class. The person class has never been declared because our preprocessor jumped from person.h to school.h back to person.h back to school.h, only processing #include directives.
The compiler starts going through the school class definition. The next interesting thing is the line std::vector<person> personVect;. You have tried to instantiate a vector<person>. But person here is unknown (i.e. has not been declared in this scope) because of (5). This explains your two template argument errors: A vector<person> is actually implicitly a vector <person, allocator<person> >. The first template argument is person and the second is allocator<person>. Since person is unknown, both these arguments are invalid.
The solution explained
The fact that school.h includes person.h, and person.h includes school.h, is what causes the cyclic dependency that you alluded to. To avoid this, we need an alternative way to declare that we are going to be using a particular class in a file. The common approach is to use a forward declaration - the statement class person; that I mentioned in the solution, before the definition of school. This is an ordinary declaration that lets the compiler know that person (as used in the school class) refers to a class.
However, in order to construct vector<person>, the compiler also needs to know how much space the class person occupies in memory (i.e. its size), which we aren't providing (and could never manually provide) with the declaration class person;. In fact, the compiler only knows the size of a class once the full definition in the header file has been processed. But if we try to do that, we're back to square one (cyclic dependency, and what not). What we do know is the size of a pointer to person, since that's machine specific (e.g. on a 32-bit machine, the size of a pointer to anything is 32 bits). Hence, we can instantiate a vector<person*> since this is always a vector of 32-bit objects regardless of what person actually is.
Try this,
person.h
#ifndef PERSON_H
#define PERSON_H
#include <string>
#include <vector>
class school;
class person {
public:
std::string name;
std::string phone;
school doSomethingWithSchool();
void test();
person();
~person();
};
#endif // PERSON_H
school.h
#ifndef SCHOOL_H
#define SCHOOL_H
#include <vector>
class person;
class school
{
public:
school();
~school();
std::vector<person*> personVect;
};
#endif // SCHOOL_H
person.cpp
#include "person.h"
#include "school.h"
#include <iostream>
using namespace std;
person::person()
{
name = "marcus";
phone = "0400000000";
}
person::~person()
{
}
void person::test() {
cout << this->name;
}
school person::doSomethingWithSchool() {
school s;
return s;
}
and in main.cpp
int main()
{
person *p = new person;
school s;
std::cout << p->name << std::endl;
s.personVect.push_back(p);
std::cout << s.personVect.size() << std::endl;
std::cout << s.personVect.at(0)->name << std::endl;
p->test();
delete p;
return 0;
}
Instead of including person #include "person.h"
In header file ("school.h") just write class person; and use pointer to person
And in c++ module ("school.cpp") include "person.h" if you need.
This will also have some benefits in feature. (reduce compilation time)
Useful links:
http://www.codeproject.com/Articles/547275/Whyplusisplusitplusbuildingplussopluslong-3f
https://stackoverflow.com/a/553869/328260

C++: Strange header error showing up

#ifndef _MY_OPENCLPLATFORM_
#define _MY_OPENCLPLATFORM_
#include "OpenCL.h"
namespace my
{
class OpenCLPlatform
{
cl_platform_id mplatformID;
cl_uint mnumDevices;
std::vector<OpenCLDevice> mdevices; // OpenCLDevice was not declared in this scope
public:
OpenCLPlatform(cl_platform_id platformID);
void getDevices();
void printInfo();
cl_platform_id& getPlatformID();
};
}
#endif
#ifndef _MY_OPENCLDEVICE_
#define _MY_OPENCLDEVICE_
#include "OpenCL.h"
namespace my
{
class OpenCLDevice
{
cl_device_id mdeviceID;
public:
OpenCLDevice(cl_device_id device);
void printInfo();
void printDeviceType(cl_device_type deviceType);
};
}
#endif
#ifndef _MY_OPENCL_
#define _MY_OPENCL_
#if defined(__APPLE__) || defined(MACOSX)
#include <OpenCL/opencl.h> // This works only for XCODE compiler
#else
#include <CL/cl.h>
#endif
#include <cassert>
#include <iostream>
#include <vector>
#include "Exception.h"
#include "OpenCLDevice.h"
#include "OpenCLPlatform.h"
namespace my {
class OpenCLDevice;
class OpenCLPlatform;
class OpenCL;
class OpenCL
{
cl_uint mnumPlatforms;
std::vector<OpenCLPlatform> mplatforms;
void getPlatforms();
public:
OpenCL();
~OpenCL();
void quickSetup();
void printPlatformVersions();
};
}
#endif
Does the the ordering "class OpenCLDevice; class OpenCLPlatform; class OpenCL;" matter? Sometimes, header files depend on each other which can lead to "hard to follow" or convoluted inclusions...Do you have a "one way" technique to deal with convoluted inclusions that you use all the time?
Edit:
I changed the code to match my real problem. If you look at the code above, the compiler is saying that 'OpenCLDevice was not declared in this scope'.
Edit:
I finally got the code to work, and this is what I did:
1. add #include "OpenCLDevice.h"in OpenCLPlatform.h
2. compile
3. remove #include "OpenCLDevice.h"in OpenCLPlatform.h
4. compile
It works now!
Edit:
I cleaned the project and removed all dependencies, and I'm getting the same errors again.
Edit:
I think compiler did something to the code. It may have chose to not include libraries that aren't used in the header and source file, but are used in other headers and source codes
Since you are including classa.h and classb.h where both classes are (presumably) defined, you shouldn't even need the forward declaration.
However, if you did not include them, then no, order of the declarations wouldn't matter. As long as as a class is forward declared before it is used you should be OK.
I see two potential issues:
Your #include "OpenCL.h" may not include the file you expect (yours), but instead some system file.
Forward declarations can't be used in your case. It works only when you have pointers or references to class instances. Your vector<OpenCLPlatform> requires the class declaration (i.e. inclusion of the corresponding header).