Compile error trying to put a unique_ptr into a map - c++

I have a Load-Method which builds my unique_ptr (will be more than one later on) and a method to add these unique_ptr to my unordered map. But the code does not compile and I guess it has something to do with scoping...
Here is the code:
#include <unordered_map>
#include <memory>
class MyClass
{
public:
std::string Name;
};
using Map = std::unordered_map<std::string,std::unique_ptr<MyClass>>;
class MyContainer
{
private:
Map myMap;
void AddItem(std::unique_ptr<MyClass> item)
{
myMap.emplace("test", item);
}
public:
void LoadItems()
{
//Read a file ... do something before etc..
std::unique_ptr<MyClass> someItem(new MyClass);
someItem->Name = "FooBar";
AddItem(someItem);
}
};
This is one of the g++ error messages:
error: use of deleted function 'std::unique_ptr<_Tp,
_Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = MyClass; _Dp = std::default_delete]'
What is the best way to get this working? I tried changing the signature of the AddItem-method like so:
void AddItem(std::unique_ptr<MyClass>& item) //takes a reference now...
This leads to a real cryptic error message:
In instantiation of 'constexpr std::pair<_T1, _T2>::pair(_U1&&, const
_T2&) [with _U1 = const char (&)[5]; = void; _T1 = const std::basic_string; _T2 = std::unique_ptr]': e:\devtools\winbuilds\include\c++\4.8.3\bits\hashtable_policy.h:177:55:
required from 'std::__detail::_ ...
I suggest trying this piece of code on the fly here, to see the error messages:
http://cpp.sh/

You cannot copy a unique_ptr, because then it will not be unique. You have to move it - AddItem(std::move(someItem)); and myMap.emplace("test", std::move(item));.

You are trying to copy unique_ptr which is not allowed (that constructor is deleted as gcc says in the error). Instead of that you can try with std::move:
#include <unordered_map>
#include <memory>
#include <utility>
class MyClass
{
public:
std::string Name;
};
using Map = std::unordered_map<std::string,std::unique_ptr<MyClass>>;
class MyContainer
{
private:
Map myMap;
void AddItem(std::unique_ptr<MyClass> item)
{
myMap.emplace("test", std::move(item));
}
public:
void LoadItems()
{
//Read a file ... do something before etc..
std::unique_ptr<MyClass> someItem(new MyClass);
someItem->Name = "FooBar";
AddItem(std::move(someItem));
}
};
Be aware, do not use the moved object afterwards.
You can consider to use shared_ptr instead.

Related

error: use of deleted function 'ClassName::ClassName(const ClassName&)'

I keep getting this error when compiling, but I don't know why. I have looked at this post and this one, but they appeared to be different problems.
The relavent code structure is:
// main.cpp
#include "MyClass.h"
int main() {
MyClass newClass = MyClass();
}
// MyClass.h
#include <string>
#include <sstream>
#include <vector>
using namespace std;
class Node;
class MyClass {
private:
vector<Node*> nodes;
int number;
stringstream fileInfo;
public:
MyClass();
~MyClass();
};
// MyClass.cpp
#include "MyClass.h"
MyClass::MyClass() {
number = 1;
}
MyClass::~MyClass() {}
The error I get when compiling is:
main.cpp: In function 'int main()':
main.cpp:4:29: error: use of deleted function 'MyClass(const MyClass&)'
MyClass new Class = MyClass();
^
In file included from main.cpp:1:0:
MyClass.h:7:7: note: 'MyClass::MyClass(const MyClass&)' is implicitly deleted because the definition would be ill-formed:
class MyClass {
^
MyClass.h:7:7: error: use of deleted function 'std::__cxx11::basic_stringstream<_CharT, _Traits, _Alloc>::basic_stringstream(const std::__cxx11:basic_stringstream<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]'
In file included from MyClass.h:2:0,
from main.cpp:1:
/usr/included/c++/5/sstream:721:7: note: declared here
basic_stringstream(const basic_stringstream&) = delete;
^
I have tried initializing all the class members in the constructor, but that didn't change the error. Other than that I can't think of what is wrong.
The problem is that your class is not copy-able because it contains a std::stringstream (which is itself not copy-able). This results in its copy constructor being deleted, which is what the compiler is trying to tell you. To fix this, simply don't use the copy-initialization syntax in your main function.
int main() {
MyClass newClass;
}

Rcpp requires a copy constructor

I'm trying to export some C++11 functionality to R, using Rcpp. Some of these functions return their result using a std::unique_ptr. This stuff cannot be copied. The MCVE below uses std::unique_ptr<std::string> to illustrate the errors.
I have created a class around the unique_ptr, in the hopes of making all of this possible, but to no avail. This is the PtrClassOwner below. The function createClassWrapper calls the original createClass, to stick the unique_ptr in a PtrClassOwner object.
#include <RcppCommon.h>
#include <memory>
#include <string>
// Stuff to wrap:
using PtrClass = std::unique_ptr<std::string>;
PtrClass createClass() { return PtrClass{new std::string("boo")}; }
// ---
class PtrClassOwner {
public:
PtrClass string;
};
PtrClassOwner createClassWrapper() { return PtrClassOwner{createClass()}; }
RCPP_EXPOSED_WRAP(PtrClassOwner); // Rcpp-extending vignette says RCPP_EXPORT_WRAP, which doesn't exist.
RCPP_EXPOSED_AS(PtrClassOwner);
#include <Rcpp.h>
RCPP_MODULE(Class){
using namespace Rcpp;
class_<PtrClassOwner>("PtrClass");
function("createClass", &createClassWrapper);
}
This the first error reported by GCC (v 5.4, on Linux):
In file included from /home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/RcppCommon.h:195:0,
from rcpp_module.cpp:1:
/home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/Rcpp/internal/wrap.h: In instantiation of ‘SEXPREC* Rcpp::internal::wrap_dispatch(const T&, Rcpp::traits::wrap_type_module_object_tag) [with T = PtrClassOwner; SEXP = SEXPREC*]’:
/home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/Rcpp/internal/wrap_end.h:30:38: required from ‘SEXPREC* Rcpp::wrap(const T&) [with T = PtrClassOwner; SEXP = SEXPREC*]’
/home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/Rcpp/internal/wrap_end.h:35:20: required from ‘SEXPREC* Rcpp::module_wrap_dispatch(const T&, Rcpp::traits::normal_wrap_tag) [with T = PtrClassOwner; SEXP = SEXPREC*]’
/home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/Rcpp/internal/wrap.h:922:40: required from ‘SEXPREC* Rcpp::module_wrap(const T&) [with T = PtrClassOwner; SEXP = SEXPREC*]’
/home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/Rcpp/module/Module_generated_CppFunction.h:34:50: required from ‘SEXPREC* Rcpp::CppFunction0<RESULT_TYPE>::operator()(SEXPREC**) [with RESULT_TYPE = PtrClassOwner; SEXP = SEXPREC*]’
rcpp_module.cpp:26:1: required from here
/home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/Rcpp/internal/wrap.h:759:54: error: use of deleted function ‘PtrClassOwner::PtrClassOwner(const PtrClassOwner&)’
return Rcpp::internal::make_new_object<T>(new T(object));
^
rcpp_module.cpp:9:7: note: ‘PtrClassOwner::PtrClassOwner(const PtrClassOwner&)’ is implicitly deleted because the default definition would be ill-formed:
class PtrClassOwner {
^
The problem seems to be that, to wrap the object into an R object, it needs to be copied. This other question is from someone running into a similar issue, but there are no answers.
I have created a similar interface to Python, where the Python object just contains a pointer to the C++ object. I find it strange that Rcpp tries to copy the object to wrap it.
Is there a way around this issue? Is it possible to wrap only a pointer to the object in an R type, and somehow still properly manage its lifetime? I'm open to any solutions, I'm not set on using Rcpp, it just seemed the most straightforward method to export this functionality.
The simplest solution I've found so far is to extract the pointer from the std::unique_ptr and create a std::shared_ptr from it. Rcpp will wrap this, as it can be copied.
#include <Rcpp.h>
#include <memory>
#include <string>
// Stuff to wrap:
using PtrClass = std::unique_ptr<std::string>;
PtrClass createClass() { return PtrClass{new std::string("boo")}; }
// ---
using ShPtrClass = std::shared_ptr<PtrClass::element_type>;
class PtrClassOwner {
public:
ShPtrClass shPtrClass;
PtrClassOwner(PtrClass ptr) : shPtrClass(ptr.release()) {}
};
PtrClassOwner createClassWrapper() { return PtrClassOwner{createClass()}; }
std::string getString(PtrClassOwner const& ptr) {
return *(ptr.shPtrClass);
}
RCPP_EXPOSED_CLASS(PtrClassOwner);
RCPP_MODULE(Class){
using namespace Rcpp;
class_<PtrClassOwner>("PtrClass");
function("createClass", &createClassWrapper, "createClass method");
function("getString", &getString, "getString method");
}

push_back a class object using vector.

How to add object of class to vector in another class.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class info{
private:
int id;
string name;
public:
info(int extId, string extName) {
this->id = extId;
this->name = extName;
}
};
class db {
private:
vector<info> infoVector;
public:
void pushData(info * data) {
this->infoVector.push_back(&data);
}
};
int main(){
info * testData = new info(123, "nice");
db database;
database.pushData(testData);
return 0;
}
I am creating a object of info class. The object contains one int and one string variables. Then I am creating db object and I am passing there a testData object.
I got error message while building project.
main.cpp: In member function ‘void db::pushData(info*)’:
main.cpp:23:44: error: no matching function for call to ‘std::vector<info>::push_back(info*&)’
this->infoVector.push_back(data);
^
In file included from /usr/include/c++/5/vector:64:0,
from main.cpp:2:
/usr/include/c++/5/bits/stl_vector.h:913:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = info; _Alloc = std::allocator<info>; std::vector<_Tp, _Alloc>::value_type = info]
push_back(const value_type& __x)
^
/usr/include/c++/5/bits/stl_vector.h:913:7: note: no known conversion for argument 1 from ‘info*’ to ‘const value_type& {aka const info&}’
What am I doing wrong?
It looks like you are trying to pass the address of an info * type to vector<info>::push_back, which only accepts types of const info & or info &&. Try using the dereference operator * instead of the address-of operator & when you call push_back:
this->infoVector.push_back(*data);
This isn't a great way to use pointers, however, and could lead to memory leakage or segfaults if data is removed from the vector or if it is deleted. It is better for the vector to own its members, so you might consider doing this instead:
class db {
private:
vector<info> infoVector;
public:
void pushData(info data) { // note: not a pointer
this->infoVector.push_back(data); // note: not address-of
}
};
int main(){
info testData(123, "nice"); // note: not a pointer
db database;
database.pushData(testData);
return 0;
}
Otherwise, if you really want infoVector to contain pointers, declare it as:
std::vector<info*> infoVector;
Then remove the address-to operator.
P.S., avoid using namespace std whenever possible!
You have vector<info> and you want to put info *, try to do:
int main(){
info testData(123, "nice");
db database;
database.pushData(testData);
return 0;
}

Error while adding shared pointer to the vector

abstract base class:
#ifndef BUILDINGORG_H
#define BUILDINGORG_H
#include <iostream>
#include <memory>
#include <vector>
class BuildingOrg
{
public:
BuildingOrg(int _id);
virtual int addBuildingComponent(std::shared_ptr<BuildingOrg> buildingOrg,
std::string _type) const;
virtual void removeBuildingComponent(std::shared_ptr<BuildingOrg> buildingOrg);
virtual void getInfo()=0;
private:
int id;
std::string type;
};
#endif // BUILDINGORG_H
concrete subclass:
#ifndef BUILDINGCOMPONENT_H
#define BUILDINGCOMPONENT_H
#include "buildingorg.h"
class BuildingComponent : public BuildingOrg
{
public:
BuildingComponent(int _id);
int addBuildingComponent(std::shared_ptr<BuildingOrg> _buildingOrg,
std::string _type) const override;
void removeBuildingComponent(std::shared_ptr<BuildingOrg> buildingOrg)
override;
void getInfo() override;
private:
std::vector<std::shared_ptr<BuildingOrg>> building_Org;
};
#endif // BUILDINGCOMPONENT_H
Implementation of subclass:
#include "buildingcomponent.h"
BuildingComponent::BuildingComponent(int _id):
BuildingOrg(_id)
{
}
int BuildingComponent::addBuildingComponent(std::shared_ptr<BuildingOrg> _buildingOrg, std::string _type) const
{
building_Org.push_back(_buildingOrg);// I am having error here
return 1;
}
void BuildingComponent::removeBuildingComponent(std::shared_ptr<BuildingOrg> buildingOrg)
{
}
void BuildingComponent::getInfo()
{
}
When I try to put shared pointer in my Vector I get this nasty error;
I really don't know why I am getting the error:
cpp:10: error: passing 'const std::vector<std::shared_ptr<BuildingOrg> >' as 'this' argument of 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::shared_ptr<BuildingOrg>; _Alloc = std::allocator<std::shared_ptr<BuildingOrg> >; std::vector<_Tp, _Alloc>::value_type = std::shared_ptr<BuildingOrg>]' discards qualifiers [-fpermissive]
building_Org.push_back(_buildingOrg);
I don’t understand what is it saying.
The const in int addBuildingComponent(std::shared_ptr<BuildingOrg> _buildingOrg, std::string _type) const override; is a promise that addBuildingComponent will not change BuildingComponent. However, it tries to modify the member variable building_Org with the push_back()...
Removing the const from addBuildingComponent() should fix the error.
The discards qualifiers part of the error message refers to the conflict with the const qualifier of the member function.
C++ template related error messages can be notoriously difficult to parse at first, but it does get easier with practice :-)
You defined BuildingComponent::addBuildingComponent method as const (i.e. that it won't change member varialbles), but you are adding passed in value to a member list (i.e. changing the member variable).
addBuildingComponent() is a const method. within its scope, *this is const, and so this->building_Org is const.
std::vector::push_back() is a non-const method. So it can't be called in a context where the vector is const.

Template function messed up

so im having a bit of problem with my ResourceManager class for a game im working on with c++.
so i tried to make a template function out of my regular addImage function so it will add sounds too but i got some errors which i cant really handle can you guys help me? :D
.hpp
#ifndef RESOURCE_MANAGER_HPP
#define RESOURCE_MANAGER_HPP
#include "Image.cpp"
#include "SoundBuffer.cpp"
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
typedef std::map<std::string, sz::Image*> ImagesContainer;
typedef std::map<std::string, sz::Image*>::iterator ImagesContainerIt;
typedef std::map<std::string, sz::SoundBuffer*> SoundsContainer;
typedef std::map<std::string, sz::SoundBuffer*>::iterator SoundsContainerIt;
typedef std::map<std::string, sf::Music*> MusicContainer;
typedef std::map<std::string, sf::Music*>::iterator MusicContainerIt;
namespace sz
{
// meanwhile this class is only for images, need to edit later for
// it to be also able to load sounds, etc...
class ResourceManager{
private:
ResourceManager() {};
ResourceManager(ResourceManager const&) {};
static ResourceManager *rm;
// add functions and variables here
ImagesContainer imagesContainer;
SoundsContainer soundsContainer;
MusicContainer musicContainer;
template <class type>
void AddNew(std::string imagePath);
public:
static ResourceManager *Instance();
// add functions here
template <class type>
type *Get(std::string imagePath);
};
}
#endif
.cpp
#include "ResourceManager.hpp"
#include <typeinfo>
namespace sz
{
ResourceManager *ResourceManager::rm = NULL;
ResourceManager *ResourceManager::Instance()
{
if (!rm)
rm = new ResourceManager;
return rm;
}
template <class type>
void ResourceManager::AddNew(std::string filePath)
{
type *item = new type(filePath);
if(typeid(type) == typeid(sz::Image))
imagesContainer[filePath] = item;
else if(typeid(type) == typeid(sz::SoundBuffer))
soundsContainer[filePath] = item;
else
return;
}
template <class type>
type *ResourceManager::Get(std::string filePath)
{
if(typeid(type) == typeid(sz::Image))
{
ImagesContainerIt it = imagesContainer.find(filePath);
if(it == imagesContainer.end())
{
AddNew<type>(filePath);
}
it = imagesContainer.find(filePath);
return it->second;
}
else if(typeid(type) == typeid(sz::SoundBuffer))
{
SoundsContainerIt it = soundsContainer.find(filePath);
if(it == soundsContainer.end())
{
AddNew<type>(filePath);
}
it = soundsContainer.find(filePath);
return it->second;
}
else
return NULL;
}
}
the errors #_#
g++ -Wall -c "Sprite.cpp" (in directory: /home/gannash/Desktop/Open Heroes/Engine)
In file included from Sprite.cpp:2:0:
ResourceManager.cpp: In member function ‘type* sz::ResourceManager::Get(std::string) [with type = sz::Image, std::string = std::basic_string<char>]’:
Sprite.cpp:10:65: instantiated from here
ResourceManager.cpp:50:15: error: cannot convert ‘sz::SoundBuffer*’ to ‘sz::Image*’ in return
ResourceManager.cpp: In member function ‘void sz::ResourceManager::AddNew(std::string) [with type = sz::Image, std::string = std::basic_string<char>]’:
ResourceManager.cpp:36:5: instantiated from ‘type* sz::ResourceManager::Get(std::string) [with type = sz::Image, std::string = std::basic_string<char>]’
Sprite.cpp:10:65: instantiated from here
ResourceManager.cpp:23:4: error: cannot convert ‘sz::Image*’ to ‘std::map<std::basic_string<char>, sz::SoundBuffer*>::mapped_type {aka sz::SoundBuffer*}’ in assignment
ResourceManager.cpp: In member function ‘type* sz::ResourceManager::Get(std::string) [with type = sz::Image, std::string = std::basic_string<char>]’:
ResourceManager.cpp:55:2: warning: control reaches end of non-void function [-Wreturn-type]
Compilation failed.
Ok, this is my idea after having a look at the code and error messages.
You cannot return Image and Sound from the same function like that. They are individual types. And you have to specify what type is going to be returned. When you put the if/else in your template it still will check to see if it can return all those types, and that will fail.
You have to return a BaseClass*(or whatever you want to call it) that both Image and Sound inherits from.
The templated function have to be completely defined for the compiler to able to use them. That means you have to move the body of those function from the source file to the header file.
Edit:
You have to check the how you use the template class. See for example this error message:
ResourceManager.cpp:50:15: error: cannot convert ‘sz::SoundBuffer*’ to ‘sz::Image*’ in return
Unless sz::SoundBuffer inherits from sz::Image you have a mismatch between types.
"Compile-time if" is done via template partial specialization. But here it's not even needed:
template<typename type> struct Container {
static std::map<std::string, type*> container;
};
std::map<std::string, sz::Image*>& ImagesContainer = Container<sz::Image>::container;
// etc...
template <class type>
void ResourceManager::AddNew(std::string filePath)
{
type *item = new type(filePath);
Container<type>::container[filePath] = item;
}