Prehistory: I am creating template class(HashMap< KeyType, ValueType >), which should implement abstraction of map using hash tables. To solve collisions in hash tables method of chains is used. I get error when I attempt to initialize HashMap object in main.cpp using constructor HashMap().
Error: "stack cookie instrumentation code detected a stack-based
buffer overrun."
So, the code:
Part of private section(only all member variables and method createBuckets(), which is used in constructor HashMap())
private:
/* Constant definitions */
static const int INITIAL_BUCKET_COUNT = 101;
static const int MAX_LOAD_PERCENTAGE = 70;
/* Type definition for cells in the bucket chain */
struct Cell {
KeyType key;
ValueType value;
Cell *next;
};
/* Instance variables */
vector<Cell *> buckets;
int nBuckets;
int numEntries;
/* Private methods */
/*
* Private method: createBuckets
* Usage: createBuckets(nBuckets);
* -------------------------------
* Sets up the vector of buckets to have nBuckets entries, each NULL. If
* asked to make empty vector, makes one bucket just to simplify handling
* elsewhere.
*/
void createBuckets(int new_nBuckets) {
if (new_nBuckets == 0) nBuckets = 1;
buckets = vector<Cell *>(new_nBuckets, NULL);
this->nBuckets = new_nBuckets;
numEntries = 0;
}
template <typename KeyType, typename ValueType>
HashMap<KeyType, ValueType>::HashMap() {
createBuckets(INITIAL_BUCKET_COUNT);
}
The most strange that the error happens rarely and when it does not happen, class works successufully. If I recompile the programm, there is no error and it do not happen until the next recompling. If it can matter, I use Visual Studia 2017 for writing this programm.
I suppose that problem is caused by creating of vector in method createBuckets, but I can not see any problem with this.
Related
I'm working on converting a lua program into a C++ program but I've hit a road block, I can't figure out how to convert this into C++
function newPool()
local pool = {}
pool.species = {} --imports data from local species = {}
pool.generation = 0
pool.innovation = Outputs
pool.currentSpecies = 1
pool.currentGenome = 1
pool.currentFrame = 0
pool.maxFitness = 0
return pool
end
I know many basics of both languages and i know it works in lua but i need it in C++. Can anyone help me?
Lua has something called Tables which allows you to add key-value pairs without a predefined struct as in C/C++. So the Lua code you posted is adding key-value pairs to pool (read comments in code):
local pool = {} -- Declare a new Table
pool.species = {} -- Add another Table to pool called 'species'
pool.generation = 0 -- Add the key 'generation' with value '0'
pool.innovation = Outputs -- Add the key 'innovation' with value 'Outputs'
pool.currentSpecies = 1 -- Add the key 'currentSpecies' with value '1'
pool.currentGenome = 1 -- Add the key 'currentGenome' with value '1'
pool.currentFrame = 0 -- Add the key 'currentFrame' with value '0'
pool.maxFitness = 0 -- Add the key 'maxFitness' with value '0'
In C++ you have several options. 1) you can create a struct and declare what you need (I'm guessing on some datatypes but if you have the full Lua program you can figure them out):
struct Pool
{
Species species; // You'll have to define Species in another struct
int generation;
SomeEnum innovation; // You'll have to define SomeEnum in an enum
int currentSpecies;
int currentGenome;
int currentFrame;
int maxFitness;
}
If you have a class then you can use the struct Pool shown below (add the struct Pool definition from above to the .h file below above class Kingdom):
// I'm doing this as a class since you are programming in C++ and I
// assume you will want to add more functions to operate on similar
// objects.
class Kingdom
{
public:
Kingdom();
Pool* NewPool();
private:
Pool _pool;
}
In your .cpp file:
#include "Kingdom.h"
Kingdom::Kingdom()
{
// _pool.species = whatever you define struct Species as
_pool.generation = 0;
_pool.innovation = SomeEnum::Outputs; // You'll have to define SomeEnum
_pool.currentSpecies = 1;
_pool.currentGenome = 1;
_pool.currentFrame = 0;
_pool.maxFitness = 0;
}
Pool* Kingdom::NewPool()
{
Pool* newPool = new Pool;
memcpy(newPool, &_pool, sizeof(Pool)); // Make a copy
return newPool; // Return the new copy
// The newPool value is dynamic memory so when the calling function is done
// with newPool it should delete it, example:
// Kingdom myKingdom;
// Pool* myNewPoolStruct = myKingdom.NewPool();
// ... do some coding here
// delete myNewPoolStruct;
}
Option 2) would be if all of your key-value pairs were the same type; i.e. all keys were std::string and all values were int. Remember, the Lua code is using Tables so you can create the equivalent in C++ with std::map<>. Then you could use std::map<std::string, int> as follows:
// In your .h file change
Pool* NewPool();
Pool _pool;
// to
std::map<std::string, int> NewPool();
std::map<std::string, int> _pool;
Then in your .cpp file change the constructor to:
Kingdom::Kingdom()
{
_pool["species"] = 0; // Some int representation of species
_pool["generation"] = 0;
_pool["innovation"] = 1; // Some int representation of Outputs
_pool["currentSpecies"] = 1;
_pool["currentGenome"] = 1;
_pool["currentFrame"] = 0;
_pool["maxFitness"] = 0;
}
std::map<std::string, int> NewPool()
{
std::map<std::string, int> newPool;
newPool = _pool; // Copy - double check this against std::map
return newPool; // Double check this is a true copy and not a pointer
}
With std::map you can create key-value pairs on the fly just like the Lua code you provided. In short, I'd go with the struct Pool approach because with std::map<> you'll have to remember strings which isn't good practice and your IDE should have intellisense which will always show you the contents of struct Pool whenever you hit the . or -> operators.
How it is possible to provide all three functions: msgpack_pack, msgpack_unpack and msgpack_object (also, what are meanings of them, exactly?) for a user-defined C++ class (in the same way MSGPACK_DEFINE does it for non-array POD/UD types) containing Plain Old Data arrays (such as dobule[] or char[]), so my class will play nicely with higher-level classes, containg this class in map or a vector?
Is there any examples of implementing them for your own class or at least msgpack C++ api documentation?
The only link to possible api reference i've found was http://redmine.msgpack.org/projects/msgpack/wiki ; but it is dead now.
Say, i have a struct like
struct entity {
const char name[256];
double mat[16];
};
What would be a msgpack_* member functions for it?
Thanks to guy who -1'd my question, i felt grievance and explored the actual undocumented codebase of msgpack. Here is the example of mentioned earlier functions with sort of explanation, in amount of my (vastly incomplete due to missing docs) understanding:
struct entity {
char name[256];
double mat[16];
// this function is appears to be a mere serializer
template <typename Packer>
void msgpack_pack(Packer& pk) const {
// make array of two elements, by the number of class fields
pk.pack_array(2);
// pack the first field, strightforward
pk.pack_raw(sizeof(name));
pk.pack_raw_body(name, sizeof(name));
// since it is array of doubles, we can't use direct conversion or copying
// memory because it would be a machine-dependent representation of floats
// instead, we converting this POD array to some msgpack array, like this:
pk.pack_array(16);
for (int i = 0; i < 16; i++) {
pk.pack_double(mat[i]);
}
}
// this function is looks like de-serializer, taking an msgpack object
// and extracting data from it to the current class fields
void msgpack_unpack(msgpack::object o) {
// check if received structure is an array
if(o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); }
const size_t size = o.via.array.size;
// sanity check
if(size <= 0) return;
// extract value of first array entry to a class field
memcpy(name, o.via.array.ptr[0].via.raw.ptr, o.via.array.ptr[0].via.raw.size);
// sanity check
if(size <= 1) return;
// extract value of second array entry which is array itself:
for (int i = 0; i < 16 ; i++) {
mat[i] = o.via.array.ptr[1].via.array.ptr[i].via.dec;
}
}
// destination of this function is unknown - i've never ran into scenary
// what it was called. some explaination/documentation needed.
template <typename MSGPACK_OBJECT>
void msgpack_object(MSGPACK_OBJECT* o, msgpack::zone* z) const {
}
};
I am working on an c++ hw assignment so I will try not to post too much code as possible, what we are working on is as following: we have a class that include a public swap function (along with insert and delete functions and such) and a private struct array to store the data.
something like:
Class set
public:
set(int dimension);
insert();
delete();
swap(set& swapset);
private:
struct *set;
now in the main we have set s1 and set s2, when I run swap like so: s1.swap(s2); s1 and s2 will swap the whole array and we need to keep the dimension of each array (so if s1 was set=new set[3] and s2 is set=new set[5]) after swap s1 is [5] and s2 is [3]
I was able to use insert and delete functions to swap the arrays when it was fixed dimension but I can't figure out how to change the dimension of the arrays during the swap function since the *set is private right?
thanks in advance for all the help!
edit: I added some parts of the code since I can't explain it correctly:
set::set()
:counter(0),m_size(0),flag(0)
{
m_set=new set[DEFAULT_MAX_ITEMS];
swapper=new set[DEFAULT_MAX_ITEMS];
maxsize=DEFAULT_MAX_ITEMS;
}
set::set(int x)
:counter(0),m_size(0),flag(0)
{
m_set=new set[x];
swapper=new set[x];
maxsize=x;
}
void set::swap(set& other)
{
// Exchange the contents of this set with the other one.
int tempmaxsize=maxsize;
int tempcounter=counter;
int tempmsize=m_size;
swapper=m_set;
m_set=other.m_set;
other.m_set=swapper;
m_size=other.m_size;
counter=other.counter;
maxsize=other.maxsize;
other.counter=tempcounter;
other.m_size=tempmsize;
other.maxsize=tempmaxsize;
}
private:
struct set
{
ItemType entry;
int count;
};
int maxsize;
set* m_set;
int m_size;
int counter;
int flag;
set* swapper;
error code is this:
debug assertion failed!
expression:_block_type_is_valid(phead->nblockuse)
Actually changing array sizes should be part of the swap function and so should be done in a class method. As it is a class method, it has access to private members.
takeaway.o: In function `takeaway':
project:145: undefined reference to `vtable for takeaway'
project:145: undefined reference to `vtable for takeaway'
takeaway.o: In function `~takeaway':
project:151: undefined reference to `vtable for takeaway'
project:151: undefined reference to `vtable for takeaway'
takeaway.o: In function `gameCore':
project.h:109: undefined reference to `gameCore<int>::initialData(int)'
collect2: ld returned 1 exit status
make: *** [takeaway] Error 1
I keep getting this Error from the linker , i know it has something to do with inline functions getting a vtable temporarily stored. But what that entails i am not quite sure. I would assume it has something to do with how i call gameCore's constructor in the initilization list of takeaway.cpp
I have a templated class (gameCore.h)
and a class (takeaway.cpp) that is inheriting from gameCore
The vtable error is called 3 times
1)in takeaways constructor
2) takeaways destructor
3)in gameCores constructor
I am using G++
Here is the code:
(i know it may seem hard to read but i have marked off exatcly where the erros occur)
takeaway.h
#ifndef _TAKEAWAY_H_
#define _TAKEAWAY_H_
#include<map>
#include<cctype>
#include<stack>
#include<map>
#include<iostream>
#include<string>
#include<cstdlib>
#include"gameCore.h"
#include<vector>
using namespace std;
class takeaway : public gameCore<int>
{
private:
public:
// template<class Penny>
void textualGame();
bool isNum(string str);
// template<class Penny>
stack<int> initialData(int initial);
// template<class Position>
int score (int position);
// template<class Position>
stack<int> addStack(int currentPos, stack<int> possiblePositions);
// template<class Penny>
takeaway (int initial);
// template<class Position>
~takeaway();
};
bool isNum(string str);
int charToint(char *theChar);
#endif
takeaway.cpp
/*
Description :
This game communicates with the gameCore class to determine the results
of a game of takeaway played between two computers or a computer and human.
*/
#include "takeaway.h"
/*
Description:Creates a stack represening initial data
Note:Change to a vector eventually
return : stack of int
*/
stack<int> takeaway:: initialData(int initial){
stack<int> returnStack;
int theScore = score(initial);
int final;
if(initial ==0)
{
final = 1;
}
else
{
final = 0;
}
returnStack.push(theScore);
returnStack.push(final);
return returnStack;
}
/*
Description: a textual representation of the game
Note: This is still terribly wrong
*/
void textualGame(){
cout <<"this is the best i could do for a graphical representation";
}
/*
Description: Deetermines if a number is even
Note: Helper function for determining win or loss positions
Returns: 1 if it is and 0 if it is not
*/
int takeaway::score(int position){
if(position % 2 == 0)
{
return 1;
}
return 0;
}
/*
Description: Will return a stack , withouth the given postion in it
will contain all positions possible after the given position
along with anyother that wehre in the given stack.This function
Must also update the map to represent updated positions
Takes: a position to check and a stack to return
Returns: A stack of possible positions.
*/
stack<int> takeaway::addStack(int currentPos, stack<int> possiblePositions ){
if(currentPos != 0)
{
// If even
if( currentPos % 2 == 0)
{
// Create a data aray with score of the new positon and mark it as not final
int data[] = {score(currentPos/2),0};
vector<int> theData(data, data+sizeof(data));
int pos = currentPos/2;
// Add it to the map
//this -> gamesMap[currentPos/2] = dataArray;
this -> gamesMap.insert(std::pair<int, vector<int> >(pos, theData));
// Add it to the possible positions
possiblePositions.push(pos);
}
if(currentPos % 3 == 0)
{
int data[] = {score(currentPos/3),0};
vector<int> theData(data,data+sizeof(data));
int pos = currentPos/3;
//this -> gamesMap[currentPos/3] = dataArray;
this -> gamesMap.insert(std::pair<int, vector<int> >(pos, theData));
possiblePositions.push(pos);
}
// Work for the position that represents taking one penny
int minusFinal = 0;
if(currentPos - 1 == 0)
{
minusFinal = 1;
}
int data[] = {score(currentPos - 1),minusFinal};
vector<int> theData(data,data+sizeof(data));
int pos = currentPos - 1;
// this -> gamesMap[currentPos -1] = dataArary
this->gamesMap.insert(std::pair<int,vector<int> >(pos, theData));
possiblePositions.push(pos);
}
return possiblePositions;
}
/*
Description: Constructor for the takeaway game
OA takes: a initial position, and initial data for it
*/
takeaway::takeaway(int initial):gameCore<int>::gameCore(initial){ //<--- ERROR HERE
//Constructor
}
/*
Description: Destuctor
*/
takeaway::~takeaway(){ // <--------------------- ERROR HERE
//Destructor
}
//checks input and creates game.
int main(int argc, char* argv[]){
int numberPennies ;
string game = argv[0];
if(argc == 2 && isNum(argv[1]) )
{
int pennies = charToint(argv[1]);
takeaway gameInstance(pennies ); // Creates a instance of $
}
// else if(argc == 3 && argv[1] == "play" && isNum(argv[2]) )
// {
// int pennies = charToint(argv[2]);
// takeaway<int> gameInstance(pennies); // Craete a human playab$
// }
else
{
cerr << "Error->Usage: " << game <<" [play] numberOfPennies \n";
exit (1);
}
return 0;
}
//Converts a char to a integer
int charToint(char *theChar){
int theInt = atoi(theChar);
return theInt;
}
//Determines if a string is numeric
bool isNum(string str){
for(int i = 0;i < str.length() ;i++){
if(isdigit(str[i]) != 1)
{
cerr << "Error->Input: Number must be a Positive Integer the charecter '" << str[i]<< "' invalidated your input. \n" ;
exit(1);
return false;
}
}
return true;
}
gameCore.h
/*
gameCore.h
Description:
This class created gameMap that are written as a template
They will communicate with the specific game and the algorithm
To keep track of positions ans there values.
*/
#ifndef GAMECORE_H
#define GAMECORE_H
#include <map>
#include <stack>
#include <string>
#include <vector>
using namespace std;
template <class Position>
class gameCore
{
protected:
//Best Move used by algorithim
Position bestMove;
//The current highest score used by the algorithim
int highestScore ;
//Stack to be used to remmeber what move created the score
stack<Position> movedFrom;
//Stack used for the algorithim.
stack<Position> curWorkingPos;
//The actual Map that the data will be held in.
map<Position,vector<int> > gamesMap;
public:
/*
Description : finds the data array for a poisition
takes: a Position
Returns: a array of integers /**
*/
virtual stack<int> initialData(Position pos) = 0;
/*
Description: Game must implement a way to determine a positions
score.
*/
virtual int score(Position pos) = 0;
/*
Description: A Graphical representation of the game
*/
virtual void textualGame() = 0;
/*
Description: a virtual function implemented by the child class
it will return a stack without the given position in it.This stack
will contain all positions available from the given postion as well as
all position already in the given stack. Also it will update the map with
all generated positions.
TAkes: a postion to check and a stack of currently working positons.
*/
virtual stack<Position> addStack(Position currentPos, stack<Position> possiblePositions ) = 0;
/*
Description:Constructor that
Creates a Map with positions as the key.
And an array of two integers that represent the positions
value and if we have moved here in the past.
Takes: a Initial Position and a Array of integers
*/
gameCore(Position initial){ // <-----ERROR HERE
//Determine the initial data and add it to the map and queue.
stack<int> theData = initialData(initial);
int first = theData.top();
theData.pop();
int second = theData.top();
theData.pop();
int initialData[] = {first,second};
vector<int> posData(initialData,initialData+sizeof(initialData));
gamesMap[initial] = posData;
curWorkingPos.push(initial);
}
/*
Description:
A destructor for the class
*/
~gameCore(){
//I do nothing but , this class needs a destructor
}
/*
Description: Takes the current position and returns
that positions Score.
Takes: A position
Returns:A integer that is a positions score.
*/
int getPosScore(Position thePos) const {
return this ->gamesMap.find(thePos)->second[0];
}
/*
Description: Adds values to a stack based on the current position
Takes: a poistion
*/
void updateStack(Position curPos){
this ->curWorkingPos =addStack(curPos,this ->curWorkingPos ); // get a stack from the game
// The game has a function that takes a position and a stack and based on the positions returns a stack identical to the last but with added values that represent valid moves from the postion./
}
/*
Description : Takes a positions and returns a integer
that depends on if the position is a final pos or not
Takes: A position
Returns: A Bool that represents if the position is a final(1) or not (0).
*/
// Possible change
bool isFinal(Position thePos) {
typename map<Position,vector<int> >::iterator iter = this ->gamesMap.find(thePos);
return iter->second[1] == 1 ;
}
/*
Description: Based on the given position determine if a move needs to be made.
(if not this is a end game position and it will return itself) If a move needs
to be made it will return the position to move to that is ideal.
Note: (because all positions can be represented as integers for any game , the return
type is a integer)
*/
int evaluatePosition(Position possiblePosition ){
if(isFinal(possiblePosition)) //If this is a final position
{
return getPosScore(possiblePosition); //Return the score
}
else
{
updateStack(possiblePosition); //Put all possible positions from this in thte stack
while(this -> curWorkingPos.size() != 0)
{
this -> movedFrom.push(this->curWorkingPos.front()); //take the top of the possible positions stack and set it the the moved from stack
this -> curWorkingPos.pop();
int curScore = evaluatePosition(this ->movedFrom.top()); //Recursive call for school
curScore = curScore * -1; //Negate the score
if(curScore > this -> highestScore) // if the score resulting from this position is biggest seen
{
highestScore = curScore;
this ->movedFrom.pop(); //do this first to get rid of the the lowest point
this -> bestMove = this ->movedFrom.top(); // mark where the lowest point came from
}
else
{
this -> movedFrom.pop();
}
}
}
return this -> bestMove;
}
//A Structure to determine if a position has a lower value than the second
struct posCompare{
bool operator() (Position pos1,Position pos2) const {
return (pos1.getPosScore() < pos2.getPosScore());
}
};
};
#endif
One or more of your .cpp files is not being linked in, or some non-inline functions in some class are not defined. In particular, takeaway::textualGame()'s implementation can't be found. Note that you've defined a textualGame() at toplevel, but this is distinct from a takeaway::textualGame() implementation - probably you just forgot the takeaway:: there.
What the error means is that the linker can't find the "vtable" for a class - every class with virtual functions has a "vtable" data structure associated with it. In GCC, this vtable is generated in the same .cpp file as the first listed non-inline member of the class; if there's no non-inline members, it will be generated wherever you instantiate the class, I believe. So you're probably failing to link the .cpp file with that first-listed non-inline member, or never defining that member in the first place.
The first set of errors, for the missing vtable, are caused because you do not implement takeaway::textualGame(); instead you implement a non-member function, textualGame(). I think that adding the missing takeaway:: will fix that.
The cause of the last error is that you're calling a virtual function, initialData(), from the constructor of gameCore. At this stage, virtual functions are dispatched according to the type currently being constructed (gameCore), not the most derived class (takeaway). This particular function is pure virtual, and so calling it here gives undefined behaviour.
Two possible solutions:
Move the initialisation code for gameCore out of the constructor and into a separate initialisation function, which must be called after the object is fully constructed; or
Separate gameCore into two classes: an abstract interface to be implemented by takeaway, and a concrete class containing the state. Construct takeaway first, and then pass it (via a reference to the interface class) to the constructor of the concrete class.
I would recommend the second, as it is a move towards smaller classes and looser coupling, and it will be harder to use the classes incorrectly. The first is more error-prone, as there is no way be sure that the initialisation function is called correctly.
One final point: the destructor of a base class should usually either be virtual (to allow polymorphic deletion) or protected (to prevent invalid polymorphic deletion).
If a class defines virtual methods outside that class, then g++ generates the vtable only in the object file that contains the outside-of-class definition of the virtual method that was declared first:
//test.h
struct str
{
virtual void f();
virtual void g();
};
//test1.cpp
#include "test.h"
void str::f(){}
//test2.cpp
#include "test.h"
void str::g(){}
The vtable will be in test1.o, but not in test2.o
This is an optimisation g++ implements to avoid having to compile in-class-defined virtual methods that would get pulled in by the vtable.
The link error you describe suggests that the definition of a virtual method (str::f in the example above) is missing in your project.
You may take a look at this answer to an identical question (as I understand):
https://stackoverflow.com/a/1478553
The link posted there explains the problem.
For quick solving your problem you should try to code something like this:
ImplementingClass::virtualFunctionToImplement(){...}
It helped me a lot.
Missing implementation of a function in class
The reason I faced this issue was because I had deleted the function's implementation from the cpp file, but forgotten to delete the declaration from the .h file.
My answer doesn't specifically answer your question, but lets people who come to this thread looking for answer know that this can also one cause.
it suggests that you fail to link the explicitly instantiated basetype public gameCore (whereas the header file forward declares it).
Since we know nothing about your build config/library dependencies, we can't really tell which link flags/source files are missing, but I hope the hint alone helps you fix ti.
GNU linker, in my case companion of GCC 8.1.0, well detects not re-declared pure virtual methods, but above certain complexity of class design it fails to identify missing implementation of methods and answers with a flat "V-Table Missing",
or even tends to report missing implementation, in spite it is there.
The only solution then is to verify consistency of declaration of implementation manually, method by method.
if you have virutal deconstruct function, you need to write it like this: ~SubListener() override = default; , don't forget this =default
I've written the rudiments of a class for creating dynamic structures in C++. Dynamic structure members are stored contiguously with (as far as my tests indicate) the same padding that the compiler would insert in the equivalent static structure. Dynamic structures can thus be implicitly converted to static structures for interoperability with existing APIs.
Foremost, I don't trust myself to be able to write Boost-quality code that can compile and work on more or less any platform. What parts of this code are dangerously in need of modification?
I have one other design-related question: Is a templated get accessor the only way of providing the compiler with the requisite static type information for type-safe code? As it is, the user of dynamic_struct must specify the type of the member they are accessing, whenever they access it. If that type should change, all of the accesses become invalid, and will either cause spectacular crashes—or worse, fail silently. And it can't be caught at compile time. That's a huge risk, and one I'd like to remedy.
Example of usage:
struct Test {
char a, b, c;
int i;
Foo object;
};
void bar(const Test&);
int main(int argc, char** argv) {
dynamic_struct<std::string> ds(sizeof(Test));
ds.append<char>("a") = 'A';
ds.append<char>("b") = '2';
ds.append<char>("c") = 'D';
ds.append<int>("i") = 123;
ds.append<Foo>("object");
bar(ds);
}
And the code follows:
//
// dynamic_struct.h
//
// Much omitted for brevity.
//
/**
* For any type, determines the alignment imposed by the compiler.
*/
template<class T>
class alignment_of {
private:
struct alignment {
char a;
T b;
}; // struct alignment
public:
enum { value = sizeof(alignment) - sizeof(T) };
}; // class alignment_of
/**
* A dynamically-created structure, whose fields are indexed by keys of
* some type K, which can be substituted at runtime for any structure
* with identical members and packing.
*/
template<class K>
class dynamic_struct {
public:
// Default maximum structure size.
static const int DEFAULT_SIZE = 32;
/**
* Create a structure with normal inter-element padding.
*/
dynamic_struct(int size = DEFAULT_SIZE) : max(size) {
data.reserve(max);
} // dynamic_struct()
/**
* Copy structure from another structure with the same key type.
*/
dynamic_struct(const dynamic_struct& structure) :
members(structure.members), max(structure.max) {
data.reserve(max);
for (iterator i = members.begin(); i != members.end(); ++i)
i->second.copy(&data[0] + i->second.offset,
&structure.data[0] + i->second.offset);
} // dynamic_struct()
/**
* Destroy all members of the structure.
*/
~dynamic_struct() {
for (iterator i = members.begin(); i != members.end(); ++i)
i->second.destroy(&data[0] + i->second.offset);
} // ~dynamic_struct()
/**
* Get a value from the structure by its key.
*/
template<class T>
T& get(const K& key) {
iterator i = members.find(key);
if (i == members.end()) {
std::ostringstream message;
message << "Read of nonexistent member \"" << key << "\".";
throw dynamic_struct_access_error(message.str());
} // if
return *reinterpret_cast<T*>(&data[0] + i->second.offset.offset);
} // get()
/**
* Append a member to the structure.
*/
template<class T>
T& append(const K& key, int alignment = alignment_of<T>::value) {
iterator i = members.find(key);
if (i != members.end()) {
std::ostringstream message;
message << "Add of already existing member \"" << key << "\".";
throw dynamic_struct_access_error(message.str());
} // if
const int modulus = data.size() % alignment;
const int delta = modulus == 0 ? 0 : sizeof(T) - modulus;
if (data.size() + delta + sizeof(T) > max) {
std::ostringstream message;
message << "Attempt to add " << delta + sizeof(T)
<< " bytes to struct, exceeding maximum size of "
<< max << ".";
throw dynamic_struct_size_error(message.str());
} // if
data.resize(data.size() + delta + sizeof(T));
new (static_cast<void*>(&data[0] + data.size() - sizeof(T))) T;
std::pair<iterator, bool> j = members.insert
({key, member(data.size() - sizeof(T), destroy<T>, copy<T>)});
if (j.second) {
return *reinterpret_cast<T*>(&data[0] + j.first->second.offset);
} else {
std::ostringstream message;
message << "Unable to add member \"" << key << "\".";
throw dynamic_struct_access_error(message.str());
} // if
} // append()
/**
* Implicit checked conversion operator.
*/
template<class T>
operator T&() { return as<T>(); }
/**
* Convert from structure to real structure.
*/
template<class T>
T& as() {
// This naturally fails more frequently if changed to "!=".
if (sizeof(T) < data.size()) {
std::ostringstream message;
message << "Attempt to cast dynamic struct of size "
<< data.size() << " to type of size " << sizeof(T) << ".";
throw dynamic_struct_size_error(message.str());
} // if
return *reinterpret_cast<T*>(&data[0]);
} // as()
private:
// Map from keys to member offsets.
map_type members;
// Data buffer.
std::vector<unsigned char> data;
// Maximum allowed size.
const unsigned int max;
}; // class dynamic_struct
There's nothing inherently wrong with this kind of code. Delaying type-checking until runtime is perfectly valid, although you will have to work hard to defeat the compile-time type system. I wrote a homogenous stack class, where you could insert any type, which functioned in a similar fashion.
However, you have to ask yourself- what are you actually going to be using this for? I wrote a homogenous stack to replace the C++ stack for an interpreted language, which is a pretty tall order for any particular class. If you're not doing something drastic, this probably isn't the right thing to do.
In short, you can do it, and it's not illegal or bad or undefined and you can make it work - but you only should if you have a very desperate need to do things outside the normal language scope. Also, your code will die horrendously when C++0x becomes Standard and now you need to move and all the rest of it.
The easiest way to think of your code is actually a managed heap of a miniature size. You place on various types of object.. they're stored contiguously, etc.
Edit: Wait, you didn't manage to enforce type safety at runtime either? You just blew compile-time type safety but didn't replace it? Let me post some far superior code (that is somewhat slower, probably).
Edit: Oh wait. You want to convert your dynamic_struct, as the whole thing, to arbitrary unknown other structs, at runtime? Oh. Oh, man. Oh, seriously. What. Just no. Just don't. Really, really, don't. That's so wrong, it's unbelievable. If you had reflection, you could make this work, but C++ doesn't offer that. You can enforce type safety at runtime per each individual member using dynamic_cast and type erasure with inheritance. Not for the whole struct, because given a type T you can't tell what the types or binary layout is.
I think the type-checking could be improved. Right now it will reinterpret_cast itself to any type with the same size.
Maybe create an interface to register client structures at program startup, so they may be verified member-by-member — or even rearranged on the fly, or constructed more intelligently in the first place.
#define REGISTER_DYNAMIC_STRUCT_CLIENT( STRUCT, MEMBER ) \
do dynamic_struct::registry< STRUCT >() // one registry obj per client type \
.add( # MEMBER, &STRUCT::MEMBER, offsetof( STRUCT, MEMBER ) ) while(0)
// ^ name as str ^ ptr to memb ^ check against dynamic offset
I have one question: what do you get out of it ?
I mean it's a clever piece of code but:
you're fiddling with memory, the chances of blow-up are huge
it's quite complicated too, I didn't get everything and I would certainly have to pose longer...
What I am really wondering is what you actually want...
For example, using Boost.Fusion
struct a_key { typedef char type; };
struct object_key { typedef Foo type; };
typedef boost::fusion<
std::pair<a_key, a_key::type>,
std::pair<object_key, object_key::type>
> data_type;
int main(int argc, char* argv[])
{
data_type data;
boost::fusion::at_key<a_key>(data) = 'a'; // compile time checked
}
Using Boost.Fusion you get compile-time reflection as well as correct packing.
I don't really see the need for "runtime" selection here (using a value as key instead of a type) when you need to pass the right type to the assignment anyway (char vs Foo).
Finally, note that this can be automated, thanks to preprocessor programming:
DECLARE_ATTRIBUTES(
mData,
(char, a)
(char, b)
(char, c)
(int, i)
(Foo, object)
)
Not much wordy than a typical declaration, though a, b, etc... will be inner types rather than attributes names.
This has several advantages over your solution:
compile-time checking
perfect compliance with default generated constructors / copy constructors / etc...
much more compact representation
no runtime lookup of the "right" member