I was trying to create a singleton to access a global-like class. This class work perfectly except when I use the std::map inside.
(yes i know, putting methods in .h..., but it's for debugging):
panthera.h
class Panthera
{
private:
std::map<std::string, std::map<long, Object *>> entities;
public:
Panthera(void);
~Panthera(void);
static Panthera * GetInstance()
{
static Panthera *engine_ = new Panthera();
return engine_;
}
void Run() {std::cout << "I run" << std::endl;}
void DOESNOTWORK(Object *o) {this->entities["test"][0] = o;}
};
main.cpp
Panthera::GetInstance()->Run(); // no problem
Panthera::GetInstance()->DOESNOTWORK(); // access violation
Been trying to solve this for some time now... Any leads?
After looking into things with OneonOne i understood that the problem was the class Object (it work if I replace it by anempty class)
tried to look in this class for incoherency/other but can't find the root of the problem, so here is the class
Object.h
#pragma once
#include "Vector2.h"
#include <list>
class Object
{
protected:
Vector2 location;
float rotation;
std::string plane;
unsigned long id;
std::list<Object *> children;
public:
Object(void);
Object(Vector2 const & location, std::string const & plane = "background", float rotation = 0);
Object(Object const & other);
~Object(void);
public:
virtual void SetLocation(Vector2 const & location);
virtual Vector2 GetLocation() const;
virtual void SetRotation(float);
virtual float GetRotation() const;
virtual void Move(Vector2 const & displacement);
virtual void Rotate(float angle);
virtual void Adopt(Object * other, Vector2 const & mountPoint = Vector2());
virtual Vector2 Mount(Vector2 const & other) const;
std::string GetPlane() const;
long GetId() const;
};
the implementation is trivial, and the class in itself run fine EXCEPT when it is added in a std::map and this only from a singleton...
As usual, thank you in advance for any help (and ask if you need the source file (or the Vector2 class))
As requested, the Object.cpp file
#include "Object.h"
#include "Matrix.h"
#include "Panthera.h"
Object::Object(void): location(Vector2()), rotation(0), plane("background")
{
this->id = reinterpret_cast<long>(this);
Panthera::GetInstance()->DOESNOTWORK(this);
}
Object::Object(Vector2 const & location, std::string const & plane, float rotation): location(location), rotation(rotation), plane(plane)
{
this->id = reinterpret_cast<long>(this);
//Panthera::GetInstance().Add(this);
}
Object::Object(Object const & other)
{
*this = other;
this->id = reinterpret_cast<long>(this);
// Panthera::GetInstance().Add(this);
}
Object::~Object(void)
{
}
void Object::SetLocation(Vector2 const & location)
{
this->Move(location - this->location);
}
Vector2 Object::GetLocation() const
{
return this->location;
}
void Object::SetRotation(float rotation)
{
this->Rotate(rotation - this->rotation);
}
float Object::GetRotation() const
{
return this->rotation;
}
void Object::Move(Vector2 const & displacement)
{
std::list<Object *>::iterator it;
for (it = this->children.begin() ; it != this->children.end(); ++it)
{
(*it)->Move(displacement);
}
this->location += displacement;
}
void Object::Rotate(float angle)
{
std::list<Object *>::iterator it;
for (it = this->children.begin() ; it != this->children.end(); ++it)
{
(*it)->SetLocation(Matrix::Transform((*it)->GetLocation() - this->location, angle) + this->location);
}
this->rotation += angle;
}
void Object::Adopt(Object * other, Vector2 const & mountpoint)
{
other->SetLocation(this->Mount(Matrix::Transform(mountpoint, this->rotation)));
this->children.push_back(other);
}
Vector2 Object::Mount(Vector2 const & other) const
{
return Vector2(this->location + other);
}
std::string Object::GetPlane() const
{
return this->plane;
}
long Object::GetId() const
{
return this->id;
}
Update: just calling the constructor of Object fails. for some reason it doesn't let me use the singleton in his constructor, => this is the root of the problem
Resolved: the problem was having a Object in the singleton class, the Object constructor made use of the singleton before it was initialized.
Your code doesn't even compile because your Constructor and Destruct weren't implemented.
Here's a C++11 version :
#include <unordered_map>
#include <iostream>
#include <string>
class Object {};
class Panthera {
private:
std::unordered_map<std::string, std::unordered_map<long, Object *>> entities;
Panthera() noexcept {}
public:
static Panthera & GetInstance() noexcept {
static Panthera engine_;
return engine_;
}
void Run() {std::cout << "I run" << std::endl;}
void worksnow() {this->entities["test"][0] = new Object;}
void get_test() {
std::cout << this->entities["test"].size() << std::endl;
}
};
int main() {
Panthera::GetInstance().Run(); // no problem
Panthera::GetInstance().worksnow(); //works too
Panthera::GetInstance().get_test();
return 0;
}
Test :
|---> clang++ -std=c++11 -stdlib=libc++ -lc++abi -I. test-singleton.cpp && ./a.out
I run
1
The original code works fine for me, so your problem is compiler related or with the omitted code :
#include <iostream>
#include <string>
#include <map>
class Object {};
class Panthera {
private:
std::map<std::string, std::map<long, Object *> > entities;
public:
Panthera(void) {}
~Panthera(void) {}
static Panthera * GetInstance() {
static Panthera *engine_ = new Panthera();
return engine_;
}
void Run() {std::cout << "I run" << std::endl;}
void DOESNOTWORK() {
this->entities["test"][0] = new Object;
std::cout << this->entities["test"].size() << std::endl;
}
};
int main() {
Panthera::GetInstance()->Run(); // no problem
Panthera::GetInstance()->DOESNOTWORK(); // access violation
return 0;
}
Related
I've run into an issue where a parameter (a user type) I pass into Lua function from C++ causes a crash when the Lua object is destroyed. Note I am using Sol2 in addition to Lua.
I discovered this is happening because Lua appears to be creating a copy of the parameter I passed in, and once the lua object is destroyed, it also destroys that copy. However, one of the member variables of that copy is a pointer to another object. Thus deleting it, deletes the pointer held by the original object, and when accessed causes the crash.
Is there anyway around this? Such as not copying the object but using a pointer to it, or not deleting objects not "owned" by lua/sol2.
I've created a sample project to demonstrate the issue.
LuaWrapper.h
#pragma once
#include <string>
#include <map>
#pragma warning(push, 0)
#define SOL_ALL_SAFETIES_ON 1
#include "sol.hpp"
#pragma warning(pop)
class SharedClass;
class LuaWrapper
{
public:
LuaWrapper();
~LuaWrapper();
public:
void RunFuncWithSharedClassParam(
const SharedClass& shared_class);
protected:
// Returns true if script loaded
bool LoadScriptIfNeeded(
const std::string& file_path);
virtual void RegisterUserTypes(
sol::state& lua_state);
private:
sol::function GetFunction(
const std::string& file_path,
const std::string& function_name);
protected:
typedef std::map<std::string, sol::state> LuaStates;
LuaStates m_lua_states;
private:
// No copies, do not implement
LuaWrapper(const LuaWrapper& rhs) = delete;
LuaWrapper& operator=(const LuaWrapper& rhs) = delete;
};
LuaWrapper.cpp
#include "LuaWrapper.h"
#include "SharedClass.h"
LuaWrapper::LuaWrapper()
{
}
LuaWrapper::~LuaWrapper()
{
std::cout << "~LuaWrapper Called" << std::endl;
}
void LuaWrapper::RunFuncWithSharedClassParam(
const SharedClass& shared_class)
{
sol::function FuncWithSharedClassParam = GetFunction("C:\\Users\\Omega\\source\\repos\\TestingSolution\\x64\\Debug\\LuaFile.lua", "FuncWithSharedClassParam");
if (FuncWithSharedClassParam)
{
FuncWithSharedClassParam(shared_class);
}
}
// Returns true if script loaded
bool LuaWrapper::LoadScriptIfNeeded(
const std::string& file_path)
{
if (!file_path.empty() && m_lua_states.find(file_path) == m_lua_states.end())
{
m_lua_states.emplace(file_path, sol::state());
m_lua_states[file_path].open_libraries(sol::lib::base);
RegisterUserTypes(m_lua_states[file_path]);
sol::protected_function_result result = m_lua_states[file_path].safe_script_file(file_path, &sol::script_pass_on_error);
if (!result.valid())
{
sol::error err = result;
std::string what = err.what();
std::cout << "LuaWrapper::LoadScriptIfNeeded()" << "Failed to load script:" << file_path << " - " << what << std::endl;
return false;
}
return true;
}
return false;
}
void LuaWrapper::RegisterUserTypes(
sol::state& lua_state)
{
lua_state.new_usertype<SharedClass>(
// Lua Class Name
"SharedClass",
// Member Function Binding
"Print", &SharedClass::Print);
}
sol::function LuaWrapper::GetFunction(
const std::string& file_path,
const std::string& function_name)
{
if (!function_name.empty())
{
LoadScriptIfNeeded(file_path);
LuaStates::const_iterator it = m_lua_states.find(file_path);
if (it != m_lua_states.end() && it->second[function_name].valid())
{
sol::function func = it->second[function_name];
return func;
}
}
return NULL;
}
SharedClass.h
#pragma once
class SamplePtr;
#include <string>
class SharedClass
{
public:
SharedClass(
const int id,
const std::string name);
~SharedClass();
void Print() const;
private:
const int m_id;
const SamplePtr* m_ptr;
// Don't create copies, only one instance of this specific object (with this m_id) can exist for the entire program.
SharedClass() = delete;
// Unfortunately, Lua/Sol is using this to copy (commenting out causes compile errors)
//SharedClass(const SharedClass& rhs) = delete;
SharedClass& operator=(const SharedClass& rhs) = delete;
};
SharedClass.cpp
#include "SharedClass.h"
#include "SamplePtr.h"
#include <string>
#include <iostream>
SharedClass::SharedClass(
const int id,
const std::string name) :
m_id(id),
m_ptr(new SamplePtr(name))
{
}
SharedClass::~SharedClass()
{
std::cout << "~SharedClass Called" << std::endl;
delete m_ptr;
}
void SharedClass::Print() const
{
std::cout << "Shared Classs ID: " << std::to_string(m_id) << " (" << m_ptr->m_name << ")" << std::endl;
}
SamplePtr.h
#pragma once
#include <string>
class SamplePtr
{
public:
SamplePtr(
const std::string& name);
const std::string m_name;
private:
SamplePtr() = delete;
SamplePtr(const SamplePtr& rhs) = delete;
SamplePtr& operator=(const SamplePtr& rhs) = delete;
};
SamplePtr.cpp
#include "SamplePtr.h"
SamplePtr::SamplePtr(
const std::string& name) :
m_name(name)
{
}
Main.cpp
#include <iostream>
#include "LuaWrapper.h"
#include "SharedClass.h"
int main()
{
// Once created, this object cannot be modified (const).
const SharedClass* sample0 = new SharedClass(0, "Ptr0");
// Create lua in it's own scope, so it's deleted.
{
LuaWrapper lua;
lua.RunFuncWithSharedClassParam(*sample0);
}
// Try to access sample0's pointer and it's deleted at this point (via the LuaWrapper deletion)...
sample0->Print();
}
LuaFile.lua
function FuncWithSharedClassParam(shared_class)
shared_class:Print();
end
I received a response from the Sol developer, https://github.com/ThePhD/sol2/issues/1340.
Pretty much just need to pass in the pointer for no copy!
I have the generic class which can store a value and a type of the value encoded as a string.
#include <iostream>
#include <string>
#include <memory>
#include <cassert>
struct IValueHolder
{
virtual ~IValueHolder() = default;
virtual const std::string& getType() = 0;
virtual void setType(const std::string& t_type) = 0;
};
template<class T>
class ValueHolder : public IValueHolder
{
private:
T m_value;
std::string m_type;
public:
ValueHolder(T t_value) : m_value(t_value){}
virtual const std::string& getType() override
{
return m_type;
}
virtual void setType(const std::string& t_type) override
{
m_type= t_type;
}
const T& getValue() const
{
return m_value;
}
};
std::unique_ptr<IValueHolder> build_int_property()
{
auto p32{ std::make_unique<ValueHolder<int32_t>>(0) };
p32->setType("int32");
return std::move(p32);
}
int main()
{
auto v32 = dynamic_cast<ValueHolder<int32_t>*>(build_int_property().get());
assert(v32->getValue() == 0); // FAILS
assert(v32->getType() == "int32"); // FAILS
return EXIT_SUCCESS;
}
And I have another utility function build_int_property which builds an integer property. But unfortunately, the tests fail. Can anyone explain what is going wrong here?
I got a template class Atlas that will store objects of Animal class and derived classes of Animal;
here's the code:
#include <iostream>
#include <assert.h>
#include <list>
using namespace std;
class Animal {
protected:
std::string m_name;
Animal (std::string name): m_name {name} {}
public:
virtual std::string regn() const { return "???"; }
virtual ~Animal(){
cout << "Destructor animal"<<'\n';}
};
class Nevertebrate : public Animal{
public:
virtual std::string regn() const { return "nevertebrate";}
virtual ~Nevertebrate();
};
class Vertebrate: public Animal {
protected:
/* std::string m_name;
Vertebrate (std::string name)
:m_name {name} {} */
Vertebrate (std::string name)
: Animal {name} {}
public:
virtual std::string regn() const { return "vertebrate";}
virtual ~Vertebrate(){
cout<<"Destructor vertebrate"<<'\n';};
};
class bird: public Vertebrate {
public:
bird(std::string name)
: Vertebrate{ name }{}
void set_name (std::string nume){
m_name = nume;}
std::string get_name(){
return m_name;}
virtual std::string regn() const {return "pasare";}
virtual ~bird (){
cout << "destructor bird"<<'\n';}
};
template <class T>
class Atlas
{
private:
int m_length{};
T* m_data{};
public:
void SetLength(int j);
Atlas(int length)
{
assert(length > 0);
m_data = new T[length]{};
m_length = length;
}
Atlas(const Atlas&) = delete;
Atlas& operator=(const Atlas&) = delete;
~Atlas()
{
delete[] m_data;
}
void erase()
{
delete[] m_data;
m_data = nullptr;
m_length = 0;
}
T& operator[](int index)
{
assert(index >= 0 && index < m_length);
return m_data[index];
}
int getLength() const;
};
template <class T>
int Atlas<T>::getLength() const
{
return m_length;
}
template <class T>
void Atlas<T>::SetLength(int j){m_length = j;
}
int main()
{
Atlas<Bird> AtlasBird(10);
Bird b;
AtlasBird.SetLength(11);
AtlasBird[10] = b --- it gets a memoryleak from here.
return 0;
}
I want to overload the += operator so that i can insert a new object into my Atlas, (e.g. AtlasAnimal).
I tried with the SetLength function to increase the length, (e.g. AtlasAnimal.SetLength(11)) but when i try to assign AtlasAnimal[10] an object (e.g. Bird b) it drops a memory leak.
I'm sorry if there was a similar question answered, but i couldn't find anything that helps
Edit: I had copied the base template for the statisticscompiler class from another solution, and it seems I somehow had ended up editing the original one while including the new one (that hadn't been edited yet) which is what led to the errors. So a tale of caution against copy pasting code into another file with the same name.
I will just post the header files because I think that's what matters here, let me know if otherwise and I can post the cpp. I have one base class that collects statistics from a process, with two derived classes and then a class that let's me use several statistics classes at once
Statistics.h
#pragma once
#define STATISTIC_H
#include <vector>
#include "Arrays.h"
class Statistics
{
public:
Statistics() {}
virtual void DumpOnePath(MJArray results) = 0;
virtual std::vector<std::vector<double>> GetResultsSoFar() const = 0;
virtual Statistics* clone() const = 0;
virtual ~Statistics() {}
private:
};
class StatisticsMean : public Statistics
{
public:
StatisticsMean();
virtual void DumpOnePath(MJArray results) ;
virtual std::vector<std::vector<double>> GetResultsSoFar() const ;
virtual Statistics* clone() const;
private:
MJArray RunningSums;
unsigned long PathsDone;
};
class StatisticsQuantiles : public Statistics
{
public:
StatisticsQuantiles(double p_lower_, double p_upper_);
virtual void DumpOnePath(MJArray results);
virtual std::vector<std::vector<double>> GetResultsSoFar() const;
virtual Statistics* clone() const;
private:
std::vector<MJArray> RunningResults;
unsigned long PathsDone;
double p_lower;
double p_upper;
};
StatisticsCompiler.h
#pragma once
#define STATISTICS_COMPILER_H
#include "statistics.h"
#include "wrapper.h"
class StatisticsCompiler : public Statistics
{
public:
StatisticsCompiler(const std::vector <Wrapper<Statistics>>& Inner_);
virtual Statistics* clone() const;
virtual void DumpOnePath(MJArray results);
virtual std::vector<std::vector<double>> GetResultsSoFar() const;
private:
std::vector <Wrapper<Statistics>> Inner;
};
And in my main class I'm trying to do this:
StatisticsMean meanGatherer;
StatisticsQuantiles quantileGatherer(p_lower, p_upper);
vector<Wrapper<Statistics>> gathererArray{ meanGatherer, quantileGatherer};
StatisticsCompiler meanAndQuantileGatherer(gathererArray);
Which gives an error no the last line complaining that "No instance of constructor matches the argument list. Argument types are:
(std::vector<Wrapper<Statistics>, std::allocator<Wrapper<Statistics>>>)."
But isn't that exactly what I've defined the constructor to accept? at least the first part, I don't know what
std::allocator<Wrapper<Statistics>>
means.
Wrapper.h in case needed. It does the memory handling
#pragma once
#define WRAPPER_H
template< class T>
class Wrapper
{
public:
Wrapper()
{
DataPtr = 0;
}
Wrapper(const T& inner)
{
DataPtr = inner.clone();
}
~Wrapper()
{
if (DataPtr != 0)
delete DataPtr;
}
Wrapper(const Wrapper<T>& original)
{
if (original.DataPtr != 0)
DataPtr = original.DataPtr->clone();
else
DataPtr = 0;
}
Wrapper& operator=(const Wrapper<T>& original)
{
if (this != &original)
{
if (DataPtr != 0) {
delete DataPtr;
}
DataPtr = (original.DataPtr != 0) ? original.DataPtr->clone() : 0;
}
return *this;
}
T& operator*()
{
return *DataPtr;
}
const T& operator*() const
{
return *DataPtr;
}
const T* const operator->() const
{
return DataPtr;
}
T* operator->()
{
return DataPtr;
}
private:
T* DataPtr;
};
Is there any way to force to only allow const instances of class to be instantiated, and have non-const instances be detected as an error by the compiler?
is there any generic way to take an existing class, and "constify" it by removing all non-const functionality?
One possible workaround is to create a wrapper class that holds an instance of the class and only gives access to a const reference to it.
template<class T>
class Immutable {
public:
template<typename... Args>
Immutable(Args&&... args) : instance(forward<Args>(args)...) {
}
operator const T&() {
return instance;
}
const T& get() const {
return instance;
}
private:
Immutable& operator=(const Immutable& other) = delete;
T instance;
};
Suppose you have a mutable class Class:
class Class {
public:
Class() : m_value(0) {
}
Class(const Class& other) : m_value(other.m_value) {
}
Class(int value) : m_value(value) {
}
Class(int x, int y) : m_value(x + y) {
}
void change(int value) {
m_value = value;
}
int value() const {
return m_value;
}
private:
int m_value;
};
Here is how Immutable<Class> can be used:
void functionTakingConstReference(const Class& x) {
}
void functionTakingNonConstReference(Class& x) {
}
void functionTakingImmutableClass(Immutable<Class>& x) {
}
void functionTakingValue(Class x) {
}
int main(int argc, char *argv[])
{
// Any constructor of Class can also be used with Immutable<Class>.
Immutable<Class> a;
Immutable<Class> b(1);
Immutable<Class> c(2, 3);
Immutable<Class> d(c);
// Compiles and works as expected.
functionTakingConstReference(a);
functionTakingImmutableClass(a);
functionTakingValue(a);
cout << a.get().value() << endl;
// Doesn't compile because operator= is deleted.
// b = a;
// Doesn't compile because "change" is a non-const method.
// a.get().change(4);
// Doesn't compile because the function takes a non-const reference to Class as an argument.
// functionTakingNonConstReference(a);
return 0;
}
Is there any way to force to only allow const instances of class to be instantiated, and have non-const instances be detected as an error by the compiler?
No.
But you can declare all members as const. Then both const and non-const instances would behave largely in the same way and it shouldn't matter whether the instances are const.
I think you are looking for an immutable class. An easy way to get immutability is to declare all member variables as const. This way you ensure that the state of your objects will not change after construction.
This guarantee is independent of whether your object is const and even if you have non-const member functions for that class.
For example:
class Foo
{
public:
Foo(int id, double value) : m_id(id), m_value(value) { }
int Id() const { return m_id; }
double Value() const { return m_value; }
private:
const int m_id;
const double m_value;
};
Another way you could generate an immutable object of any type is through a template class. Something like this:
class Bar
{
public:
Bar(int id, double value) : m_id(id), m_value(value) { }
int Id() const { return m_id; }
double Value() const { return m_value; }
void SetId(int id) { m_id = id; }
private:
int m_id;
double m_value;
};
template<typename T>
class MyImmutable
{
public:
const T m_obj;
MyImmutable(const T& obj) : m_obj(obj)
{ }
};
int main()
{
cout << "Hello World!" << endl;
Foo a(1,2.0);
Bar x(2,3.0);
MyImmutable<Bar> y(x);
cout << "a.id = " << a.Id() << endl;
cout << "a.value = " << a.Value() << endl;
cout << "y.id = " << y.m_obj.Id() << endl;
cout << "y.value = " << y.m_obj.Value() << endl;
y.m_obj.SetId(2); // calling non-const member throws an error.
return 0;
}