How to emplace derived object into map - c++

I'm still new to C++ and have come across a problem where I can't seem to insert a new derived class to a map.
My code is simplified as follows:
std::map<int, std::unique_ptr<Base_Class> > m;
void func(){
for(int num = 0; num < 100; n++){
m.emplace(num, new Derived_Class() );
}
}
Which gives me this:
error: no matching function for call to 'std::pair <const int, std::unique_ptr<Base_Class> >::pair(int&, Derived_Class*)
I've tried unsuccessfully using:
m.emplace(std::pair(num, new Derived_Class()) );
And which gives me this:
error: no matching function for call to 'std::pair<const int, std::unique_ptr<Base_Class> >::pair(std::pair<int, Derived_Class*>)
I can't seem to figure this one out and would appreciate any help.

m.emplace(num, std::unique_ptr<Derived_Class>(new Derived_Class()));
Would be the way to go. Since the unique_ptr constructor taking a raw pointer is explicit, it cannot be implicitly initialized from a Derived_Class*. You need to explicitly create a unique_ptr object to emplace.
I posed this solution because you mentioned c++11, but the truly favorable way would be to use std::make_unique<Derived_Class>() (c++14 and onward), both to avoid repeating yourself, and to make the creation of the unique_ptr "atomic".

Related

Storing objects in an std::map

I'd like to store objects of a class in an std::map. Here is a working example showing how I am doing it currenty
#include <iostream>
#include <map>
class A
{
private:
int a;
std::string b;
public:
A(int init_a, std::string init_b) : a(init_a), b(init_b){};
void output_a() {std::cout << a << "\n";}
};
int main()
{
std::map<size_t, A> result_map;
for (size_t iter = 0; iter < 10; ++iter)
{
A a(iter, "bb");
result_map.insert(std::make_pair(iter, a));
}
return 0;
}
I have two question to this example:
Is this the professional C++-way to store objects in an std::map in the above case? Or should I create a pointer to an object of A and store that instead? I like the first (current) option as I don't have to worry about memory management myself by using new and delete - but most importantly I'd like to do things properly.
How would I go about calling a member function of, say, result_map[0]? I naively tried result_map[0].output_a(), but that gave me the error: error: no matching function for call to ‘A::A()’
Is this the professional C++-way to store objects in an std::map in the above case?
It is fine, simpler code could be:
result_map.emplace(iter, A(iter, "bb") );
you should use whatever you find more readable. By the way calling integer counter iter is not a way to write a readable code.
How would I go about calling a member function of, say, result_map[0]?
You better use std::map::find:
auto f = result_map.find( 0 );
if( f != result_map.end() ) f->output_a();
problem with operator[] in your case - it has to create and instance if object does not exist with that index but you do not have default ctor for A.
1- It depends: If your class can be copied and you're not worried about performance issues with copying objects into the map, then that's a good way to do it. However, if say your class held any immutable data (std::mutex for example) you'd have to use a pointer, as the copy constructor c++ automatically generates would be ill formed, so it merely wouldn't be able to copy the class
2- result_map.at(0).output_a() or result_map.at(0)->output_a() if you're using a map of pointers

Why am I getting compile error "use of deleted function 'std::unique_ptr ..."

Am getting a huge compile error with message
c:\mingw\include\c++\6.1.0\bits\predefined_ops.h:123:18: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Deduction; _Dp = std::default_delete<Deduction>]'
{ return bool(_M_comp(*__it1, *__it2)); }
when I pass a custom comparator to STL set_difference function.
My code:
struct Value{
std::string ded_code;
float amount;
Value(std::string code, float amt):ded_code(code), amount(amt){}
};
struct Deduction{
std::string p_number;
std::vector<std::unique_ptr<Value>> values;
Deduction(string pnum, string code, float amt):p_number(pnum){
auto val = std::make_unique<Value>(code, amt);
values.emplace_back(move(val));
}
};
class compute{
public:
vector<unique_ptr<Deduction>> deductions;
void fillDeductions(){
// fill deductions
...
}
};
class CompareDiff{
public:
bool operator()(unique_ptr<Deduction>& ded1, unique_ptr<Deductions>& ded2){
rPtr1 = ded1.get();
rPtr2 = ded2.get();
return ( rPtr1->p_number < rPtr2->p_number);
}
};
...
int main(){
...
// fill two deduction vectors
Compute compA = Compute()
compA.fillDeductions()
Compute compB = Compute()
compB.fillDeductions()
vector<unique_ptr<Deduction>> diffs
set_difference(compA.begin(), compA.end(),
compB.begin(), compB.end(),
inserter(diffs, diffs.begin()), CompareDiff());
}
Am using gcc 6.1.0 on windows 7 machine.
What am I missing?
Regards.
PG
The reason why you are still getting an error:
std::set_difference does copy internally:
Copies the elements from the sorted range [first1, last1) which are not found in the sorted range [first2, last2) to the range beginning at d_first.
http://en.cppreference.com/w/cpp/algorithm/set_difference
If you want your code to compile, use std::shared_ptr instead.
Keep in mind, that the Standard Library is optimized for Objects and not for pointers. You will have to do the ownership management yourself if you use pointers.
The chief feature of std::unqiue_ptr is that it cannot be copied. That's by design, and the name tells you as much.
However, CompareDiff tries to take its arguments by value. That requires a copy. Instead, take a std::unique_ptr<..> const& - no copy is needed.
You cannot copy construct a unique_ptr since its a deleted function, you can move unique pointers to transfer ownership but since you want a functor to compare something you need to pass those unique_ptr by reference.
Use a unique_ptr<x> to express that a function assumes ownership of an x.
Use a shared_ptr<x> to express that a function is part owner of an x.
If you indeed want to pass a unique_ptr and transfer ownership, you should move the smart pointer into the function argument.
More notes on passing smart pointers, and Herb Sutter has some good thoughts in this CppCon talk.

C++ stable_partition Compiler Error

I'm trying to extend an example I found in Koenig and Moo's "Accelerated C++." I've got the following code which attempts to split a vector into two partitions.
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
struct MyClass {
int* MyInt;
MyClass() : MyInt(NULL) {}
};
struct AnalyzeMemOps {
vector<MyClass> AllMyClassRecords; // Where I keep the MyClass instances
bool sameBaseReg(MyClass m);
vector<MyClass> splitBySameBase(vector<MyClass>& main);
AnalyzeMemOps() {}
};
// Predicate function for stable_partition
bool AnalyzeMemOps::sameBaseReg(MyClass m) {
return true;
}
vector<MyClass> AnalyzeMemOps::splitBySameBase(vector<MyClass>& main) {
vector<MyClass>::iterator it =
stable_partition(main.begin(), main.end(), sameBaseReg); // Error is here
vector<MyClass> sameBases(it, main.end());
main.erase(it, main.end());
// Print results
cout << "Split By Same Base: Returning SameBase Instrs\n";
for (vector<MyClass>::iterator i = sameBases.begin(); i != sameBases.end(); ++i) {
cout << " " << i->MyInt << "\n";
}
return sameBases;
}
int main() {
AnalyzeMemOps AMCR;
MyClass m;
AMCR.AllMyClassRecords.push_back(m);
AMCR.AllMyClassRecords.push_back(m);
AMCR.AllMyClassRecords.push_back(m);
vector<MyClass> t = AMCR.splitBySameBase(AMCR.AllMyClassRecords);
}
I get an error when I attempt to compile this file with g++:
Tile.cpp: In member function \u2018std::vector<MyClass, std::allocator<MyClass> > AnalyzeMemOps::splitBySameBase(std::vector<MyClass, std::allocator<MyClass> >&)\u2019:
Tile.cpp:26: error: no matching function for call to \u2018stable_partition(__gnu_cxx::__normal_iterator<MyClass*, std::vector<MyClass, std::allocator<MyClass> > >, __gnu_cxx::__normal_iterator<MyClass*, std::vector<MyClass, std::allocator<MyClass> > >, <unresolved overloaded function type>)\u2019
/usr/include/c++/4.4/bits/stl_algo.h:1864: note: candidates are: _BIter std::stable_partition(_BIter, _BIter, _Predicate) [with _BIter = __gnu_cxx::__normal_iterator<MyClass*, std::vector<MyClass, std::allocator<MyClass> > >, _Predicate = bool (AnalyzeMemOps::*)(MyClass)]
make: *** [a.out] Error 1
Obviously this is a toy example, but I've checked the function prototypes and I'm not sure where I'm going wrong here. Any suggestions?
The problem is that sameBaseReg is a member function of AnalyzeMemOps. You can't use it like an ordinary non-member function because it can only be called on an object.
If you have a modern compiler that supports C++0x, C++ TR1, or if you have Boost handy, you can use bind to bind the pointer to member function to the this object:
std::bind(&AnalyzeMemOps::sameBaseReg, this, std::placeholders::_1)
In the current C++ standard library, the <functional> library has std::mem_fun, std::bind1st, and other functions that can help with this, but they are an absolute beating to use effectively.
You'll need to use mem_fun to turn the member function into an function object, then use bind1st to supply the this pointer.
I was never particularly successful getting this stuff to work on a regular basis (the standard library algorithms seem to be mainly designed for use with freestanding functions or hand-written predicate classes), but something like this should do the trick:
vector<MyClass>::iterator it =
stable_partition(main.begin(),
main.end(),
bind1st(mem_fun(&AnalyzeMemOps::sameBaseReg),
this));
mem_fun gives you back a function object that takes two arguments, the first being the object to invoke mem_fun's member function on, and the second being the single argument to the member function.
bind1st takes a function object that takes two arguments, and returns you a new one that takes one argument, which when invoked via operator() will call the original function object with the bind1st's argument as its first argument and the supplied argument as the second.
The end result is that a new function object is created, that takes one argument, and that will call this->sameBaseReg, passing in the supplied argument.

C++ overloading operator= in template

Hi all I'm having trouble with C++ template operator=
What I'm trying to do:
I'm working on a graph algorithm project using cuda and we have several different formats for benchmarking graphs. Also, I'm not entirely sure what type we'll end up using for the individual elements of a graph.
My goal is to have a templated graph class and a number of other classes, each of which will know how to load a particular format. Everything seems to work alright except the point where the graphCreator class returns a graph type from the generate function.
Here is my code:
Graph opertator=:
MatrixGraph<T>& operator=(MatrixGraph<T>& rhs)
{
width = rhs.width;
height = rhs.height;
pGraph = rhs.pGraph;
pitch = rhs.pitch;
sizeOfGraph = rhs.sizeOfGraph;
rhs.Reset();
}
the rhs.reset() call removes all references to allocated memory so they will not be deallocated by rhs. Only one graph is allowed to have a reference to the allocated graph memory.
Graph copy constructor:
MatrixGraph(MatrixGraph<T>& graph)
{
(*this) = graph;
}
Graph Creator load function:
MatrixGraph<T> LoadDIMACSGraphFile(std::istream& dimacsFile)
{
char inputType;
std::string input;
GetNumberOfNodesAndEdges(dimacsFile, nodes, edges);
MatrixGraph<T> myNewMatrixGraph(nodes);
while(dimacsFile >> inputType)
{
switch(inputType)
{
case 'e':
int w,v;
dimacsFile >> w >> v;
myNewMatrixGraph[w - 1][v - 1] = 1;
myNewMatrixGraph[v - 1][w - 1] = 1;
break;
default:
std::getline(dimacsFile, input);
break;
}
}
return myNewMatrixGraph;
}
And finally in main.cpp where I'm trying to unit test this I use it:
DIMACSGraphCreator<short> creator;
myGraph = creator.LoadDIMACSGraphFile(instream);
When I try to compile I get this error:
main.cpp: In function 'int main(int, char**)':
main.cpp:31: error: no match for 'operator=' in 'myGraph = DIMACSGraphCreator<T>::LoadDIMACSGraphFile(std::istream&) [with T = short int](((std::istream&)(& instream.std::basic_ifstream<char, std::char_traits<char> >::<anonymous>)))'
MatrixGraph.h:103: note: candidates are: MatrixGraph<T>& MatrixGraph<T>::operator=(MatrixGraph<T>&) [with T = short int]
make: *** [matrixTest] Error 1
just a guess, are you by chance missing const qualifiers in your copy constructor and assignment?
The problem is you're returning by value (correctly) but trying to bind that temporary object to a non-const reference (for the op= parameter). You can't do this.
The solution is to change things around, which can result in non-idiomatic code; use an auto_ptr_ref-like construct, which gets around this in a fairly bad-but-encapsulated way; or use r-value references, which are designed for exactly this situation. However, r-value references are only available as part of C++0x, and your compiler may not support them yet.
Make sure to return *this in your op= as well. Without warnings turned on your compiler may silently (and against the standard) accept that function without a return statement. (I don't know why.)
Example of the first solution:
// move return value into output-parameter:
void LoadDIMACSGraphFile(std::istream& dimacsFile, MatrixGraph<T>& dest);
// ...
DIMACSGraphCreator<short> creator;
creator.LoadDIMACSGraphFile(instream, myGraph);
std::auto_ptr is in the the stdlib, and uses a special "holder" class named auto_ptr_ref to implement move semantics.

How do I pass a Generic::List by reference?

In an attempt to wrap some unmanaged code in a managed .dll I'm trying to convert a Generic::List of data points into a std::vector. Here's a snippet of what I'm trying to do:
namespace ManagedDLL
{
public ref class CppClass
{
void ListToStdVec( const List<double>& input_list, std::vector<double>& output_vector )
{
// Copy the contents of the input list into the vector
// ...
}
void ProcessData( List<double> sampleData )
{
std::vector<double> myVec;
ListToStdVec( sampleData, myVec );
// Now call the unmanaged code with the new vector
// ...
}
}
}
Compiling this gives me:
error C3699: '&' : cannot use this indirection on type 'const System::Collections::Generic::List'
I've probably missed something fundamental here (I'm relatively new to .net's way of doing things), but that looks like reasonably valid code to me.. ?
[Edit] I've tried both Andy and Dario's suggestions and they work, but how do I then access the members of the input list? I've tried all sorts of combinations of dreferencing and nothing seems to compile:
void ListToStdVec( const List<double>% input_list, std::vector<double>& output_vector )
{
int num_of_elements = input_list->Count;
}
void ListToStdVec( const List<double>^ input_list, std::vector<double>& output_vector )
{
int num_of_elements = input_list.Count;
}
...both give me:
error C2662: 'System::Collections::Generic::List::Count::get' : cannot convert 'this' pointer from 'const System::Collections::Generic::List' to 'System::Collections::Generic::List %'
...so how do you access the reference / pointer?
According to Herb Sutter, % is the managed object pass by reference character. Convert the code to the following, and it should work:
void ListToStdVec( const List<double>% input_list, std::vector<double>& output_vector
{
// Copy the contents of the input list into the vector
// ...
}
Edit: I think the const is causing the issues, although I'm not sure why. If you change the List argument to not be const, then the first function will compile if you use the -> operator, while the second function will compile if you use the . operator (I'm not sure why that difference exists - it doesn't make much sense).
That said, if all that you want to do is to copy the elements in the List to the vector, then you really want to use ^. Think of that as having a reference to the managed object. I think that % would be used if you want to pass the reference "by reference" (i.e. reassign input_list to something else within ListToStdVec(), and have the caller see the result of that assignment. However, given that you use the . operator to access members when using %, that tells me that I may not understand the purpose of that at all.
As List<T> is a managed .NET class, it's passed by managed GC-Handle denoted by ^ and not by C++-reference.
Ex:
void ListToVec(List<double>^ input_list, std::vector<double>& out)
You don't need additional const here. The notation List<T>^% creates a tracking reference (comparable to C++-pointers) rather than a call by reference.
Just access the members by list->... and list[...].