I would like to store the value that is passed to the constructor in a static set returned by a static function.
It seems that the insertion is successful, but when it reach the end of the scope of the constructor it disappear.
I have reproduced it in a simple example:
// container.hh
#pragma once
#include <vector>
#include <set>
class container {
public:
container(const int& s);
static std::set<int, std::less<int>>& object_set_instance();
};
#include "container.hxx"
// container.hxx
#pragma once
#include "container.hh"
#include <iostream>
container::container(const int& s)
{
auto set = object_set_instance();
set.insert(s);
std::cout << "Size " << set.size() << "\n";
}
std::set<int, std::less<int>>& container::object_set_instance()
{
static std::set<int, std::less<int>> s;
return s;
}
#include "container.hh"
#include <iostream>
int main()
{
auto a = container(42);
auto b = container(21);
auto b1 = container(51);
auto b2 = container(65);
auto b3 = container(99);
}
Output :
Size 1
Size 1
Size 1 // Size never change
Size 1
Size 1
Why doesn't the set's size change ?
auto set = object_set_instance();
If you use your debugger to inspect what set is, you will discover that it's a std::set and not a std::set& reference. Effectively, a copy of the original std::set is made (object_set_instance() returns a reference, only to copy-construct a new object that has nothing to do with the referenced one), and the next line of code modifies the copy, and it gets thrown away immediately afterwards.
This should be:
auto &set = object_set_instance();
A debugger is a very useful tool for solving these kinds of Scooby-Doo mysteries, and it would clearly reveal what's going on here. If you haven't yet had the opportunity to learn how to use one, hopefully this will inspire you to take a look, and join Mystery, Inc. as a member in good standing.
Related
I have created a priority_queue with custom comparator which stores string in lexicographically sorted order, and it works as expected.[ Ref. this] ]
Now, I want it to be value in an unordered_map, and I got error: no matching constructor for initialization ... and closest thing I found is this. I realize I need to pass the comparator to the constructor as well, but how?
Here is my code as of now :
#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
using namespace std; // Used to make code less verbose
int main() {
auto cmp = [](string s1, string s2){
return s1.compare(s2) > 0;
};
using myQuque = priority_queue<string, vector<string>, decltype(cmp)> ;
// This code works
myQuque pq(cmp);
pq.push("ZZ");
pq.push("AA");
pq.push("CC");
while(!pq.empty()){
cout << pq.top() << " ";
pq.pop();
}
// This doesn't. How do I pass 'cmp' to constructor?
unordered_map<string, myQuque> table;
auto p = table["r"];
p.push("ZZ");
p.push("AA");
}
https://godbolt.org/z/cvPfPd
I then realized that I can use multiset as well for this application, but I still would like to know how can I use priority_queue with custom comparator in map.
Using a lambda was a bad idea... just provide comparison through the comparison template argument, then no constructor argument is required...
#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
using namespace std; // Used to make code less verbose
struct Cmp {
bool operator()(const string& s1, const string& s2) const {
return s1.compare(s2) > 0;
}
};
int main() {
using myQuque = priority_queue<string, vector<string>, Cmp>;
// This code works
myQuque pq;
pq.push("ZZ");
pq.push("AA");
pq.push("CC");
while(!pq.empty()){
cout << pq.top() << " ";
pq.pop();
}
// This doesn't. How do I pass 'cmp' to constructor?
unordered_map<string, myQuque> table;
auto p = table["r"];
p.push("ZZ");
p.push("AA");
}
Note too I've changed the comparison to take arguments by const reference, avoiding deep copying the text being compared for each comparison (at least whenever longer than any Short-String-Optimisation buffer your std::string implementation might have).
Maps use the default constructor when creating new elements. You could use pointers, but you’d need to allocate each new entry:
unordered_map<string, shared_ptr<myQuque>> table;
auto p = make_shared<myQueue>(cmp);
table["r"] = p;
p->push("ZZ");
p->push("AA");
Problem is that with custom run-time comparator, default constructor of myQuque is not available.
std::unordered_map::operator[] must be able to use default constructs for value in case there is no value ready for specyfic key. This is needed since it returns a reference to value which can be used in assignment expression.
To fix it you have to drop operator[], you can use this:
unordered_map<string, myQuque> table;
auto &p = table.emplace("r", cmp).first->second;
p.push("ZZ");
p.push("AA");
demo: https://godbolt.org/z/bPnrEe
As an alternative you can provide static comparator to priority_queue as Tony Delroys answer. In such case myQuque will have default constructor and problem vanishes.
I have a struct which contains a reference to a vector.
I then create a vector of this struct.
I create three three instances of this struct in this vector.
I then erase the second instance of the struct in the vector.
This apparently causes the contents of testData2 to become the same as the contents of testData3!?
How do I stop this from happening? Is there something I should put in the destructor of the struct to stop this from happening?
Or is what I am doing here terribly bad and if so, why?
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
struct TESTSTRUCT
{
int &testInt;
std::vector<int> &testVector;
TESTSTRUCT(int &testIntInput, std::vector<int> &testVectorInput)
:testInt(testIntInput), testVector(testVectorInput) {}
TESTSTRUCT(const TESTSTRUCT &source)
:testInt(source.testInt), testVector(source.testVector) {}
TESTSTRUCT &operator=(const TESTSTRUCT &source)
{
testInt = source.testInt;
testVector = source.testVector;
return *this;
}
virtual ~TESTSTRUCT(){}
};
int main()
{
std::vector<int> testData1;
std::vector<int> testData2;
std::vector<int> testData3;
int a = 1;
int b = 2;
int c = 3;
testData1.push_back(10);
testData1.push_back(20);
testData1.push_back(30);
testData2.push_back(40);
testData2.push_back(50);
testData2.push_back(60);
testData3.push_back(70);
testData3.push_back(80);
testData3.push_back(90);
std::vector<TESTSTRUCT> *structVector = new std::vector<TESTSTRUCT>();
structVector->push_back(TESTSTRUCT(a, testData1));
structVector->push_back(TESTSTRUCT(b, testData2));
structVector->push_back(TESTSTRUCT(c, testData3));
std::cout<<&testData1[0]<<std::endl;
std::cout<<&testData2[0]<<std::endl;
std::cout<<&testData3[0]<<std::endl;
std::cout<<testData1[0]<<std::endl;
std::cout<<testData2[0]<<std::endl;
std::cout<<testData3[0]<<std::endl;
structVector->erase(structVector->begin()+1);
std::cout<<testData1[0]<<std::endl;
std::cout<<testData2[0]<<std::endl;
std::cout<<testData3[0]<<std::endl;
std::cout<<&testData1[0]<<std::endl;
std::cout<<&testData2[0]<<std::endl;
std::cout<<&testData3[0]<<std::endl;
return 0;
}
Output:
00711220
00711258
00717C68
10
40
70
10
70
70
00711220
00711258
00717C68
Press any key to continue . . .
EDIT:
This here is an example from a larger program. The instances of the struct are for things I want a renderer to draw, and those things can change their position (and hence where the renderer should draw them).
The issue is not immediately visible. Have a look at the equality operator of TESTSTRUCT :
TESTSTRUCT &operator=(const TESTSTRUCT &source)
{
testInt = source.testInt;
testVector = source.testVector;
return *this;
}
The testVector in this will obtain a copy of source.testVector.
Now, the structVector in main contains three instances of TESTSTRUCT, each bound to its own std::vector<int> via a reference. When you call structVector->erase(structVector->begin()+1);, TESTSTRUCT(b, testData2) is removed from the structVector.
The specification of erase says that all the vector's elements after the requested erasing position are shifted down (in terms of position) in order for the vector to be memory-contiguous. I don't know if the standard specifies anything about how erase needs to be implemented when it comes to copying, but in my implementation (g++), operator= is called. This means that the vector stored via reference inside the TESTSTRUCT instance referenced by the iterator structVector->begin()+1 (so, effectively, structVector[1]) gets the contents of structVector[2]. And because it's a reference, it's essentially the same thing as testData2 from main, which explains why its content is exactly the same as testData3.
This is valid, however, as you can see yourself, avoiding such code makes sense when debugging.
You are over using references (somewhat incorrectly). Your TESTSTRUCT objects contains references to testdata1, testdata2 and testdata3. So when you modify structVector, previous two vectors also get modified. So when you erase second element from structVector, the third element takes it's position. So the internal elements, i.e. the testdata2 is also replaced with testdata3in main, as their references are contained in the struct.
I want to submit a handle but I only want it to be executed if a shared pointer is still valid:
// elsewhere in the class:
std::shared_ptr<int> node;
// later on:
const std::weak_ptr<int> slave(node); // can I do this in the capture clause somehow?
const auto hook = [=]()
{
if (!slave.expired())
//do something
else
// do nothing; the class has been destroyed!
};
someService.Submit(hook); // this will be called later, and we don't know whether the class will still be alive
Can I declare slave within the capture clause of the lambda? Something like const auto hook = [std::weak_ptr<int> slave = node,=]().... but unfortunately this doesn't work. I would like to avoid declaring the variable and then copying it (not for performance reasons; I just think it would be clearer and neater if I could create whatever the lambda needs without polluting the enclosing scope).
You can do this using generalized lambda captures in C++14:
const auto hook = [=, slave = std::weak_ptr<int>(node)]()
{
...
};
Here's a live example. Note that since there are no parameters or explicit return type, the empty parameter list (()) can be left out.
As mentioned by chris this is possible in C++14.
If you are willing to modify the captured value simply add mutablespecifier.
Here is an example which fills a vector from zero to the length of the vector.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> container(10);
std::generate(container.begin(), container.end(), [n = 0]() mutable { return n++; });
for (const auto & number : container)
{
std::cout << number << " ";
}
std::cin.ignore();
return 0;
}
I'm trying to create a std::discrete_distribution object using data passed into a class constructor. I know how to create this using static data, but cannot figure out how using variable data (cleanly). What I have now "works", but is painful. Is there a more appropriate way of doing this?
The distInit = { distArray[0], ... }; line is the problem.
#include <iostream>
#include <iomanip>
#include <initializer_list>
#include <map>
#include <random>
class Die {
private:
int loadSide;
double loadAmount;
std::mt19937 generator;
std::discrete_distribution<> distribution;
std::initializer_list<double> distInit;
std::array<double, 7> distArray;
public:
Die( int loadSide, double loadAmount ) : loadSide(loadSide), loadAmount(loadAmount) {
distArray.fill( 1 );
distArray[0] = 0;
distArray[this->loadSide] = this->loadAmount;
distInit = { distArray[0], distArray[1], distArray[2], distArray[3], distArray[4], distArray[5], distArray[6] };
distribution.param( distInit );
};
int roll( ) {
return distribution( generator );
};
};
const int ROUNDS = 10000;
int main() {
Die* die = new Die( 5, 20 );
std::map<int, int> m;
for(int n=0; n < ROUNDS; n++) {
m[die->roll()]++;
}
for(auto p : m) {
std::cout << p.first << " generated " << std::setiosflags(std::ios::fixed) << std::setprecision(2) << (float) p.second / ROUNDS << " times\n";
}
}
I may not be asking the right question, which I will apologize in advance for if so. This is a strong possibility as I'm surprised I'm unable to find any (apparently) related hits on this subject.
My compiler is g++-mp-4.8 (MacPorts gcc48 4.8-20130411_0) 4.8.1 20130411 (prerelease)
Command line /opt/local/bin/g++-mp-4.8 -std=c++11 test.cpp -o test
If you have variable data, you should be using the discrete_distribution constructor taking a pair of iterators:
template< class InputIt >
discrete_distribution( InputIt first, InputIt last );
You shouldn't be trying to construct the param_type directly; instead use a helper function to construct your distribution:
class Die {
private:
std::mt19937 generator;
std::discrete_distribution<> distribution;
static std::discrete_distribution<> makeDistribution(
int loadSide, double loadAmount )
{
std::array<double, 7> distArray;
distArray.fill( 1 );
distArray[0] = 0;
distArray[loadSide] = loadAmount;
return {std::begin(distArray), std::end(distArray)};
}
public:
Die( int loadSide, double loadAmount ) :
generator{ },
distribution{ makeDistribution( loadSide, loadAmount ) }
{}
int roll( ) {
return distribution( generator );
}
};
std::initializer_list only intended for use as a temporary object (function argument) or local variable. It's not a container and it doesn't own anything; it's an accessor to an anonymous, temporary array.
The Standard includes an example similar to your code, §8.5.4/6, which mentions
the initializer_list object is initialized in a constructor’s ctor-initializer, so the array persists only until the constructor exits, and so any use of the elements of i4 after the constructor exits produces undefined behavior.
In your case, it's the body of the constructor, not a ctor-initializer preceding the body, but the story is the same. It's just dumb luck that your program is working for now.
To store the distribution in the object, use std::array or std::vector. array is more efficient but it doesn't support arr = { … } syntax. (There are a few simple alternatives.) vector does support your syntax using braces and the = operator; this support uses an implicit std::initializer_list.
I don't know any better way to create a std::initializer_list from a container like std::array other than the one shown in the OP.
However, for the original problem, namely, passing the parameters to the distribution, I can suggest something simpler.
typedef std::discrete_distribution<>::param_type param_type;
distribution.param(param_type(distArray.begin(), distArray.end()));
The standard says that distributions must provide a type member param_type (which is the type of argument taken by param()) but doesn't specify it. However, [rand.req.dist] says that
For each of the constructors of D [the distribution type] taking arguments corresponding to parameters of the distribution, P [param_type] shall have a corresponding constructor subject to the same requirements and taking arguments identical
in number, type, and default values.
Well, it turns out that std::discrete_distribution<> has a constructor taking iterators pointing to the range of parameters. Therefore, whatever std::discrete_distribution<>::param_type is, it must have a similar constructor. Therefore, I'm suggesting creating a param_type from distArray.begin() and distArray.end() and pass it to distribution.param().
A side note: You no longer need std::initializer_list<double> distInit; in your class. It seems to me that you don't need std::array<double, 7> distArray as a class member either (it could be a local variable in Die's constructor).
I'm trying to use a Boost MultiIndex container in my simulation. My knowledge of C++ syntax is very weak, and I'm concerned I'm not properly removing an element from the container or deleting it from memory. I also need to modify elements, and I was hoping to confirm the syntax and basic philosophy here too.
// main.cpp
...
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/tokenizer.hpp>
#include <boost/shared_ptr.hpp>
...
#include "Host.h" // class Host, all members private, using get fxns to access
using boost::multi_index_container;
using namespace boost::multi_index;
typedef multi_index_container<
boost::shared_ptr< Host >,
indexed_by<
hashed_unique< const_mem_fun<Host,int,&Host::getID> >
// ordered_non_unique< BOOST_MULTI_INDEX_MEM_FUN(Host,int,&Host::getAge) >
> // end indexed_by
> HostContainer;
typedef HostContainer::nth_index<0>::type HostsByID;
int main() {
...
HostContainer allHosts;
Host * newHostPtr;
newHostPtr = new Host( t, DOB, idCtr, 0, currentEvents );
allHosts.insert( boost::shared_ptr<Host>(newHostPtr) );
// allHosts gets filled up
int randomHostID = 4;
int newAge = 50;
modifyHost( randomHostID, allHosts, newAge );
killHost( randomHostID, allHosts );
}
void killHost( int id, HostContainer & hmap ){
HostsByID::iterator it = hmap.find( id );
cout << "Found host id " << (*it)->getID() << "Attempting to kill. hmap.size() before is " << hmap.size() << " and ";
hmap.erase( it ); // Is this really erasing (freeing from mem) the underlying Host object?
cout << hmap.size() << " after." << endl;
}
void modifyHost( int id, HostContainer & hmap, int newAge ){
HostsByID::iterator it = hmap.find( id );
(*it) -> setAge( newAge ); // Not actually the "modify" function for MultiIndex...
}
My questions are
In the MultiIndex container allHosts of shared_ptrs to Host objects, is calling allHosts.erase( it ) on an iterator to the object's shared_ptr enough to delete the object permanently and free it from memory? It appears to be removing the shared_ptr from the container.
The allhosts container currently has one functioning index that relies on the host's ID. If I introduce an ordered second index that calls on a member function (Host::getAge()), where the age changes over the course of the simulation, is the index always going to be updated when I refer to it?
What is the difference between using the MultiIndex's modify to modify the age of the underlying object versus the approach I show above?
I'm vaguely confused about what is assumed/required to be constant in MultiIndex.
Thanks in advance.
Update
Here's my attempt to get the modify syntax working, based on what I see in a related Boost example.
struct update_age {
update_age():(){} // have no idea what this really does... elicits error
void operator() (boost::shared_ptr<Host> ptr) {
ptr->incrementAge(); // incrementAge() is a member function of class Host
}
};
and then in modifyHost, I'd have hmap.modify(it,update_age). Even if by some miracle this turns out to be right, I'd love some kind of explanation of what's going on.
shared_ptr will remove actual Host object in its destructor (if there is no other instances of shared_ptr). All objects in MultiIndex are considered constant. To modify the object you should use method modify of MultiIndex. In that case indexes will be updates if necessary.
You could use the following functor to change age field:
struct change_age
{
change_age(int age) : age_(age) {}
void operator()(boost::shared_ptr<Host> h) // shared_ptr !!!
{
h->age = age_;
}
private:
int age_;
};
Then use it as follows:
testHosts.modify( it, Host::change_age( 22 ) ); // set age to 22