I'm having trouble understanding why this isn't working as I expect it to. It may be that I'm using Visual Studio 2013, but hey.
This code is part of the item randomization system in a game engine I'm writing.
// the chance a rarity will have a given number of affixes
std::unordered_map<ItemRarities, ChanceSelector<int>> affixCountChances = {
std::pair<ItemRarities, ChanceSelector<int>>(ItemRarities::Cracked,
{ ChanceSelector<int>(
{ ChancePair(int, 100, 0) }) }),
std::pair<ItemRarities, ChanceSelector<int>>(ItemRarities::Normal,
{ ChanceSelector<int>(
{ ChancePair(int, 80, 0),
ChancePair(int, 20, 1) }) }),
// snip for conciseness (there are 3 more)
};
And this is the ChanceSelector class:
using Percentage = int;
#define ChancePair(T, p, v) std::pair<Percentage, T>(p, v)
template <class T>
class ChanceSelector
{
private:
std::unordered_map<T, Percentage> _stuff;
public:
ChanceSelector()
{
}
~ChanceSelector()
{
if (_stuff.size() > 0)
_stuff.clear();
}
ChanceSelector(std::initializer_list<std::pair<Percentage, T>> list)
{
// snip for conciseness
}
T Choose()
{
// snip for conciseness
}
};
The above code compiles fine but I have two questions:
I don't understand why using ChanceSelector in std::pair requires a default constructor. Explicitly, it looks like I'm calling the constructor with the initializer list.
When the applications runs, it crashes with: Unhandled exception at 0x01762fec in (my
executable): 0xC0000005: Access violation reading location 0xfeeefeee.
Number 2 goes away if I only have one item in that map or if I change the definition of affixCountChances to std::unordered_map<ItemRarities, ChanceSelector<int>*> (and adjust the rest accordingly). The error dumps me at this code in list:
for (_Nodeptr _Pnext; _Pnode != this->_Myhead; _Pnode = _Pnext)
{
_Pnext = this->_Nextnode(_Pnode); // <-- this line
this->_Freenode(_Pnode);
}
Further inspection reveals the error happened in the destructor. _stuff is empty:
~ChanceSelector()
{
if (_stuff.size() > 0)
_stuff.clear();
}
It is legitly calling the destructor. Items are being removed from _stuff but I don't see why it would be calling the destructor. The crash happens after all items have been constructed and affixCountChances contains all items. I would assume that means it's destroying all the temporaries it created but I don't see why it would be creating temporaries.
Edit:
Constructor of ChanceSelector:
ChanceSelector(std::initializer_list<std::pair<Percentage, T>> list)
{
int total = 0;
int last = 100;
for (auto& item : list)
{
last = item.first;
total += item.first;
_stuff[item.second] = total;
}
// total must equal 100 so that Choose always picks something
assert(total == 100);
}
To answer your two questions:
std::pair requires a default constructor, because you can do something like
std::pair<int, MyClass> myPair();
which creates a copy of your class using the default constructor (The values of the pair are actual values and not references):
// MSVC implementation
template<class _Ty1,class _Ty2>
struct pair
{ // store a pair of values
typedef pair<_Ty1, _Ty2> _Myt;
typedef _Ty1 first_type;
typedef _Ty2 second_type;
pair()
: first(), second() // Here your class gets default constructed
{ // default construct
}
// .....
_Ty1 first; // the first stored value
_Ty2 second; // the second stored value
};
The template of the pair gets fully implemented, so you need a default constructor event if you are not using the line above.
One way to avoid this dependency is to use pointers in the std::pair, this then sets the default value of the second value of the pair to nullptr:
std::pair<int, MyClass*> myPair();
0xFEEEFEEE indicates that the storage, where your pointer itself was stored has already been deleted (e.g. working on a deleted class reference).
This deletion seems to occur somewhere outside the code you have posted here.
For more Magic Numbers see Magic Numbers on Wikipedia
Edit:
Additionally, the contents of the initializer list do not exist after the constructor call. You might have there a reference copied instead of the actual object, which then gets deleted. The msvc implementation of the std::unordered_map uses a std::list as base for storing items. I'm not able to give your more information about this with the given code.
Initializer list and lifetime of its content
Edit 2: I was able to reproduce the error with your given code, it was not the content of the initializer_list ctor.
The problem seems to be the lifetime of the objects inside the initializer list.
When I move the declaration of the pairs for the unordered map out of the initializer_list for the unordered map, everything works fine:
std::pair<ItemRarities, ChanceSelector<int>> pair1( ItemRarities::Cracked,
{ ChanceSelector<int>(
{ ChancePair( int, 100, 0 ) } ) } );
std::pair<ItemRarities, ChanceSelector<int>> pair2( ItemRarities::Normal,
{ ChanceSelector<int>(
{ ChancePair( int, 80, 0 ),
ChancePair( int, 20, 1 ) } ) } );
std::unordered_map<ItemRarities, ChanceSelector<int>> chances = {
pair1,
pair2
};
I'm not completely sure why this is a problem, but I think is comes from the {} in the initializer list, those objects might get deleted, when leaving the first {} and before entering the actual intializer_list for the unordered_map
Related
I'm looking for a C++ container to store pointers to objects which also meets the following requirements.
A container that keeps the order of elements (sequence container, so std::set is not suitable)
A container that has a member function which return the actual size (As std::array::size() always returns the fixed size, std::array is not suitable)
A container that supports random accesses such as operator [].
This is my code snippet and I'd like to remove the assertions used for checking size and uniqueness of elements.
#include <vector>
#include <set>
#include "assert.h"
class Foo {
public:
void DoSomething() {
}
};
int main() {
// a variable used to check whether a container is properly assigned
const uint8_t size_ = 2;
Foo foo1;
Foo foo2;
// Needs a kind of sequential containers to keep the order
// used std::vector instead of std::array to use member function size()
const std::vector<Foo*> vec = {
&foo1,
&foo2
};
std::set<Foo*> set_(vec.begin(), vec.end());
assert(vec.size() == size_); // size checking against pre-defined value
assert(vec.size() == set_.size()); // check for elements uniqueness
// Needs to access elements using [] operator
for (auto i = 0; i < size_; i++) {
vec[i]->DoSomething();
}
return 0;
}
Is there a C++ container which doesn't need two assertions used in my code snippet? Or should I need to make my own class which encapsulates one of STL containers?
So a class that acts like a vector except if you insert, it rejects duplicates like a set or a map.
One option might be the Boost.Bimap with indices of T* and sequence_index.
Your vector-like indexing would be via the sequence_index. You might even be willing to live with holes in the sequence after an element is erased.
Sticking with STLyou could implement a bidirectional map using 2 maps, or the following uses a map and a vector:
Note that by inheriting from vector I get all the vector methods for free, but I also risk the user downcasting to the vector.
One way round that without remodelling with a wrapper (a la queue vs list) is to make it protected inheritance and then explicitly using all the methods back to public. This is actually safer as it ensures you haven't inadvertently left some vector modification method live that would take the two containers out of step.
Note also that you would need to roll your own initializer_list constructor if you wanted one to filter out any duplicates. And you would have to do a bit of work to get this thread-safe.
template <class T>
class uniqvec : public std::vector<T*>
{
private:
typedef typename std::vector<T*> Base;
enum {push_back, pop_back, emplace_back, emplace}; //add anything else you don't like from vector
std::map <T*, size_t> uniquifier;
public:
std::pair<typename Base::iterator, bool> insert(T* t)
{
auto rv1 = uniquifier.insert(std::make_pair(t, Base::size()));
if (rv1.second)
{
Base::push_back(t);
}
return std::make_pair(Base::begin()+rv1.first.second, rv1.second);
}
void erase(T* t)
{
auto found = uniquifier.find(t);
if (found != uniquifier.end())
{
auto index = found->second;
uniquifier.erase(found);
Base::erase(Base::begin()+index);
for (auto& u : uniquifier)
if (u.second > index)
u.second--;
}
}
// Note that c++11 returns the next safe iterator,
// but I don't know if that should be in vector order or set order.
void erase(typename Base::iterator i)
{
return erase(*i);
}
};
As others have mentioned, your particular questions seems like the XY problem (you are down in the weeds about a particular solution instead of focusing on the original problem). There was an extremely useful flowchart provided here a number of years ago (credit to #MikaelPersson) that will help you choose a particular STL container to best fit your needs. You can find the original question here In which scenario do I use a particular STL container?.
struct Apple { };
struct Banana { };
struct Peach { };
using FruitTuple = std::tuple<Apple, Banana, Peach>;
template<typename TTuple, typename TItem>
TTuple& getParentTuple(TItem* mItemPtr)
{
// <static assert that the tuple item types are unique>
// ...?
}
int main()
{
FruitTuple ft;
// I know these pointers point to objects inside a `FruitTuple`...
Apple* ptrApple{&std::get<0>(ft)};
Banana* ptrBanana{&std::get<1>(ft)};
Peach* ptrPeach{&std::get<2>(ft)};
// ...is there a way to get the `FruitTuple` they belong to?
auto& ftFromA(getParentTuple<FruitTuple>(ptrApple));
auto& ftFromB(getParentTuple<FruitTuple>(ptrBanana));
auto& ftFromP(getParentTuple<FruitTuple>(ptrPeach));
assert(&ftFromA == &ftFromB);
assert(&ftFromB == &ftFromP);
assert(&ftFromA == &ftFromP);
return 0;
}
How can getParentTuple<TTuple, TItem> be implemented in a standard-compliant and non-architecture-dependent way?
Not possible.
Edit:
I do not think there is anything in the standard that prevents a compliant tuple implementation from allocating the elements individually on the heap.
The elements' memory location, then, would not allow any inference that results in the tuple object's location.
The only thing that you can do is to extend your element classes to also contain a back pointer to the tuple that you then fill in after placing your elements in the tuple.
The following is code that should work with common implementations, but I'm pretty sure that it is not standard compliant, because it makes assumptions that the memory layout of the tuple is determinstic.
In a comment you said you don't care about that case, so here you go:
template<typename TTuple, typename TItem>
TTuple& getParentTuple(TItem* mItemPtr)
{
TTuple dummyTuple;
// The std::get by type will not compile if types are duplicated, so
// you do not need a static_assert.
auto dummyElement = (uintptr_t)&std::get<TItem>(dummyTuple);
// Calculate the offset of the element to the tuple base address.
auto offset = dummyElement - (uintptr_t)&dummyTuple;
// Subtract that offset from the passed element pointer.
return *(TTuple*)((uintptr_t)mItemPtr - offset);
}
Note that this constructs the tuple once, which may have unwanted side effects or performance impacts in some cases. I'm not sure if there is a compile time variant of this.
I'm a complete beginner in c++ and everything has been going on well until now. I'm new to the idea of pointers (I'm from python), and I have this weird error.
So basically, I created this "SearchNode" class, and found below is one of it's methods "getChildren" which should return a vector of other SearchNode instances, representing the possible cells to which a Knight (chessboard) could travel from it's current state. (BFS)
That said, when I finish pushing into my vector, all the elements suddenly point to 1st element only. Could someone help me out here?
PS: it's a similar problem to c++ push_back doesn't work as it is supposed ... but unlike Angela (who's was writing her own compiler), I'm a total beginner in c++. Your help with be greatly appreciated.
UPDATE
I got rid of the int*, and used array for my state. I could now successfully search the graph (therefore the states are ok) and find the shortest path, but I couldn't seem to reconstruct the path.
To test, I started at {0,0} and could find {4,4}, but the path, according to the getPath method was {4,4}, {3,6}, {3,6}, {3,6} ... (infinite loop of {3,6}). Is there something wrong with my parent pointers, or my getPath function? Thanks for your support in advance.
//Search class
class SearchNode
{
public:
//Variables
SearchNode *m_parent;
array<int,2> m_state; //I don't understand typedef's yet, will use them when I'm clearer with them :)
//Normal Constructor
SearchNode(array<int,2>& state_, SearchNode *parent_=nullptr) :
m_state(state_),
m_parent(parent_)
{}
//Method to get Next reachable states. Returns instances of SearchNode.
vector<SearchNode> getChildren()
{
int legalMoves[8][2] = {{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}};
vector<SearchNode> children;
children.reserve(8);
for(int i=0; i<8; i++)
{
int x = (m_state[0] + legalMoves[i][0]);
int y = (m_state[1] + legalMoves[i][1]);
if( (x>-1) and (x<9) and (y<9) and (y>-1)) // Within the bounds of the board
{
array<int,2> childState = {x,y};
SearchNode childNode = SearchNode(childState,this);
children.push_back(childNode);
}
}
return children;
}
void getPath()
{
cout<<"\nPath: ";
cout<< this->print();
SearchNode current = *this;
unsigned int counter = 1;
while((current.m_parent!=nullptr) and counter< 10)
{
counter++;
cout<< (current.m_parent)->print();
current = *(current.m_parent);
}
cout << (current.m_parent)->print();
}
string print()
{
stringstream out;
out << "{" << this->m_state[0] << "," << this->m_state[1] << "} ";
return out.str();
}
};
Lots of mistakes and errors, I strongly suggest you turn up the warning level in your compiler so you can get more information. With GCC/G++/Clang, try "-Wall" or "-Wextra", as moshbear points out.
Your nodes never get assigned the "parent" value, you're creating a "shadow" local variable called "parent" and assigning that. To avoid common errors like this, use a prefix or postfix for member variable names to separate them from local names, e.g. "m_parent" or "_parent".
You don't assign default values in your constructor, you explicitly leave the values uninitialized.
SearchNode()
{
//do nothing
}
and then you introduce this garbage data in your pointer-based constructor, what you probably want is
SearchNode() : parent(NULL), state(NULL) {}
Your copy constructor is a disaster. You need to read up on and understand pointers and local variables.
//Start Node constructor. Still looking for an equivalent for null.
SearchNode(int *state)
{
int genericStartState[2] = {-1,-1};
SearchNode blankParent = SearchNode();
SearchNode genericStart = SearchNode(genericStartState,&blankParent);
this->parent = &genericStart;
this->state=state;
}
Firstly, "blankParent" here is a local variable containing random data because of your current copy constructor. Secondly, you're taking the address of it - of a private, local variable, which is about to stop existing when you hit the "}" at the end of the routine.
"genericStartState" is also about to go out of scope.
And aside from that, I don't think you want or need this particular constructor.
But fundamentally, the bug in your subject, is because you do the same thing in your assignment loop -- you use a temporary, local array to store the new values, and then pass a pointer to that to your constructor. Since you are taking the address, it will be the same every loop.
int childState[2] = { x, y };
SearchNode childNode = SearchNode(childState,this);
This is why all of your nodes have the same state - because they all point to the same memory location (edit: as pointed out by DyP, that side-effect isn't something you can count on, just an artefact of ordering in this case).
It might be easier for you to use simple array of ints rather than a pointer in your node structure.
Here's how the constructor side of things might look, if your compiler is VisualStudio 2012 or G++ 4.8 or Clang 4.2.
class SearchNode
{
public:
typedef std::array<int, 2> State;
private:
// I use the 'm_' convention for members, 'g_' for globals, 's_' for statics.
SearchNode* m_parent;
State m_state;
public:
//////////
// Default ctor.
SearchNode()
: m_parent(nullptr) // C++11 constant meaning pointer with value 0
, m_state({-1, -1}) // preferred but requires recent C++11 features
{
//m_state[0] = m_state[1] = -1; // had to do this instead for gcc 4.7.3
}
//////////
// Normal ctor
// I use the '_'-postfix convention for parameter names.
SearchNode(SearchNode* parent_, const State& state_)
: m_parent(parent_)
, m_state(state_)
{
}
//////////
// Copy constructor.
// We could do this, but it's the default behavior anyway.
/*
SearchNode(const SearchNode& rhs)
: m_parent(rhs.m_parent)
, m_state(rhs.m_state)
{
}
*/
// Current C++11 compilers let us be explicit and do this:
//SearchNode(const SearchNode& rhs) = default;
// But it's the default behavior so we don't have to do this one at all.
};
The latest C++11 language changes (MSVC > 2012, GCC >= 4.8, Clang >= 4.1) would allow you to replace the first two constructors with
// Kill two birds with one stone and have default parameters on our normal ctor,
// replacing both the default and normal ctor with one function.
SearchNode(SearchNode* parent_ = nullptr, const State& state_ = { -1, -1 }))
: m_parent(parent_)
, m_state(state_)
{
}
If you had a fully C++1y compatible compiler, you could boil all that down to:
class SearchNode
{
public:
typedef std::array<int, 2> State;
private:
// I use the 'm_' convention for members, 'g_' for globals, 's_' for statics.
SearchNode* m_parent = nullptr; // c++1y keyword to replace 'NULL'
State m_state = { -1, -1 };
public:
SearchNode() = default;
SearchNode(const State& rhs_) = default; // not strictly required.
SearchNode(SearchNode* parent_, const State& state_)
: m_parent(parent_), m_state(state_)
{}
};
The following code seems to always follow the true branch.
#include <map>
#include <iostream>
class TestClass {
// implementation
}
int main() {
std::map<int, TestClass*> TestMap;
if (TestMap[203] == nullptr) {
std::cout << "true";
} else {
std::cout << "false";
}
return 0;
}
Is it defined behaviour for an uninitialized pointer to point at nullptr, or an artifact of my compiler?
If not, how can I ensure portability of the following code? Currently, I'm using similar logic to return the correct singleton instance for a log file:
#include <string>
#include <map>
class Log {
public:
static Log* get_instance(std::string path);
protected:
Log(std::string path) : path(path), log(path) {};
std::string path;
std::ostream log;
private:
static std::map<std::string, Log*> instances;
};
std::map<std::string, Log*> Log::instances = std::map<std::string, Log*>();
Log* Log::get_instance(std::string path) {
if (instances[path] == nullptr) {
instances[path] = new Log(path);
}
return instances[path];
}
One solution would be to use something similar to this where you use a special function provide a default value when checking a map. However, my understanding is that this would cause the complexity of the lookup to be O(n) instead of O(1). This isn't too much of an issue in my scenario (there would only ever be a handful of logs), but a better solution would be somehow to force pointers of type Log* to reference nullptr by default thus making the lookup check O(1) and portable at the same time. Is this possible and if so, how would I do it?
The map always value-initializes its members (in situations where they are not copy-initialized, of course), and value-initialization for builtin types means zero-initialization, therefore it is indeed defined behaviour. This is especially true for the value part of new keys generated when accessing elements with operator[] which didn't exist before calling that.
Note however that an uninizialized pointer is not necessarily a null pointer; indeed, just reading its value already invokes undefined behaviour (and might case a segmentation fault on certain platforms under certain circumstances). The point is that pointers in maps are not uninitialized. So if you write for example
void foo()
{
TestClass* p;
// ...
}
p will not be initialized to nullptr.
Note however that you might want to check for presence instead, to avoid accumulating unnecessary entries. You'd check for presence using the find member function:
map<int, TestClass*>::iterator it = TestMap.find(203);
if (it == map.end())
{
// there's no such element in the map
}
else
{
TestClass* p = it->second;
// ...
}
Yes, that's defined behaviour. If an element isn't yet in a map when you access it via operator[], it gets default constructed.
Hey I'm a little confusd about how the constructor initializes the size of the vector >.
This is my hpp
#include <vector>
#include <list>
#include <ostream>
using namespace std ;
typedef struct { double successful[2] , unsuccessful[2] ; } Perform ;
template <class DATA>
class Table {
private :
vector<list<DATA> > theList;
typename list<DATA>::iterator itr;
unsigned listSize;
unsigned actualSize;
unsigned probe;
...
and in my cpp
template <class DATA> Table<DATA>::Table(unsigned int size)
{
listSize = size;
actualSize = 0;
probe = 0;
theList(size); //Not sure how to make the vector of size "size"
}
and if I wanted to clear the lists in each vector location could I do a for loop and have the code be
theList[i].clear();
or would i have to do something different?
One last question is for inserting something into each of the lists in side the vectors, can I do
theList[i].push_back(data);
if not how do I do it?
Thanks for the help.
Congratulations, you have discovered the difference between initialization and assignment.
Assignment occurs when you try to set an existing object to a new value; initialization is when an object is created and its constructor is called.
What you're doing in your constructor (which, for some reason, isn't shown in your header, making your code more confusing than it has to be) is assignment. By the time the constructor body executes, all members have been initialized.
To initialize a member, use the initializer list syntax:
template <class DATA> Table<DATA>::Table(unsigned int size)
: listSize(size), actualSize(0), probe(0), theList(size)
{
}
This will call the constructor for each of the specified elements, with the specified arguments.
To set initial size you can use initialer list,
template <class DATA> Table<DATA>::Table(unsigned int size)
: theList(size)
{
...
or by calling resize method inside:
theList.resize(size);
For your first question, the code is right. This will create a vector with size elements, these elements will be default-constructed, which in ths case means they're empty lists. BUT you should place this initialization in the initialization list as follows (you should also do this for the other members btw).
template <class DATA> Table<DATA>::Table(unsigned int size) : theList(size)
{
...
}
This will prohibit the constructor from first calling the default constructor of your theList object (so it is a valid object).
The answer to your other questions is yes, but if you use C++11 you can probably save some tedious for-loops by using for_each and lambdas, for example like this:
std::for_each(theList.begin(),theList.end(),[&data](std::list& l) { l.push_back(data)});