Accessing a set of pointers - c++

Here is my code:
class obj140{
public:
int x;
explicit obj140(int y):x(y){ }
bool operator<(const obj140& rhs) const{
return x < rhs.x;
}
};
int main() {
obj140 * wtf = new obj140[5] {obj140(1),obj140(1),obj140(3),obj140(4),obj140(5)};
std::set<obj140> orm(wtf,wtf+5);
}
Is this possible? like copying pointers to a set? I have no errors but I have no idea on how to access it though.
How do i print out the values from orm set?

I modified your code slightly to make what's going on easier to see and as an example of one way to get a look at the items stored in the set.
class obj140
{
public:
int x;
explicit obj140(int y) :x(y)
{
}
bool operator<(const obj140& rhs) const
{
return x < rhs.x;
}
void print() const
{
std::cout << x << std::endl;
}
};
int main()
{
obj140 * wtf = new obj140[5]
{ obj140(1), obj140(1), obj140(3), obj140(4), obj140(5) };
std::set<obj140> orm(wtf, wtf + 5);
for (auto it = orm.begin(); it != orm.end(); ++it)
{
it->print();
}
delete[] wtf; //edit. Forgot to clean up the pointer.
return 0;
}
Output:
1
3
4
5
What you are doing works and loaded the set. Since sets only store unique values (and order them, which makes for a great quickie sort if you need one) the second add of obj140(1) got discarded.

Related

Quickest way to copy a nearly empty array

I have to optimize a really crappy c++ code. The guy who made it doesn't know how to code: It has memory stomps, indices are used starting from 1 instead of 0, spagetthi code, you name a bad practice and there it is.
So 40% of the time this algorithm is copying large arrays which are nearly empty. I'm trying to make minimal changes because that would probably mean changing thousands and thousands lines of code and any mistake would mean getting completely different results.
So instead of declaring this large, nearly empty arrays like this:
short HLLE[dimcl]; //define dimcl 600
I'm doing something like this
ArrayTimes HLLE;
/////
// Stores the occupied positions in another array, when copying, instead of copying all, empty the occupied ones
// then fill with the other occupied ones
class ArrayTimes
{
public:
ArrayTimes(int numTasks);
ArrayTimes(const ArrayTimes& _other);
virtual ~ArrayTimes();
inline short& operator[](int _index)
{
auto &result = (*m_times)[_index];
if (result == 0) //if there was already a value doesn't count as occupied again
{
(*m_occupied)[m_numOccupied] = _index;
++m_numOccupied;
}
return result;
}
inline const short& operator[](int _index) const
{
return (*m_times)[_index];
}
inline ArrayTimes& operator= (const ArrayTimes &_other)
{
//vaciamos
for (int i = 0; i < m_numOccupied; ++i)
{
auto occIndex = m_occupied->operator[](i);
m_times->operator[](occIndex) = 0;
}
*m_occupied = *(_other.m_occupied);
m_numOccupied = _other.m_numOccupied;
for (int i = 0; i < _other.m_numOccupied; ++i)
{
auto occIndex = _other.m_occupied->operator[](i);
m_times->operator[](occIndex) = _other.m_times->operator[](occIndex);
}
return *this;
}
ArrayTimes::ArrayTimes(int numTasks) :
m_numOccupied(0)
{
m_occupied = new std::vector<int>();
m_times = new std::vector<short>();
m_times->resize(numTasks);
m_occupied->resize(numTasks / 4);
}
ArrayTimes::ArrayTimes(const ArrayTimes& _other)
{
m_occupied = new std::vector<int>();
m_times = new std::vector<short>();
auto datosGlobales = DatosGlobalesProblema::getInstance();
auto numTareas = datosGlobales->GetNumTareas() + 1;
m_occupied = new std::vector<int>();
m_times = new std::vector<short>();
m_times->resize(numTareas);
m_occupied->resize(numTareas / 4);
operator=(_other);
}
ArrayTimes::~ArrayTimes()
{
delete m_times;
delete m_occupied;
}
int ArrayTimes::Size() const
{
return m_occupied->size();
}
I have tried several containers to store the occupied positions: list, set, unordered set, map. None of them is quicker than copying all the array positions.
I guess the right answer is finding another way to save that information without wasting memory in such arrays of memory, altough that means refactoring thousands of lines of code.
The following code has this timings with 300 to 600 copy. You don't need to copy anything manually with std::vector.
I've changed the = operator but you have to go through one of the vectors to see what you have to copy.
Also you can have more m_times than indexes in m_occupied so you shouldn't count on occupied vector.
Size: 300, 75
Element: 90
real 0m0,002s
user 0m0,002s
sys 0m0,000s
class ArrayTimes
{
std::vector<int> m_occupied;
std::vector<short> m_times;
int m_numOccupied;
public:
ArrayTimes(int numTasks) :
m_numOccupied(0)
{
m_times.resize(numTasks);
m_occupied.resize(numTasks / 4);
}
ArrayTimes(const ArrayTimes& _other)
{
auto numTareas = 600;
m_times.resize(numTareas);
m_occupied.resize(numTareas / 4);
operator=(_other);
}
~ArrayTimes()
{
}
inline short& operator[](int _index)
{
auto &result = m_times[_index];
if (result == 0) //if there was already a value doesn't count as occupied again
{
m_occupied[m_numOccupied] = _index;
++m_numOccupied;
}
return result;
}
inline const short& operator[](int _index) const
{
return m_times[_index];
}
inline ArrayTimes& operator= (const ArrayTimes &_other)
{
m_times.reserve (_other.m_times.size());
for (auto e : _other.m_occupied) {
m_times[e] = _other.m_times[e];
}
m_numOccupied = _other.m_numOccupied;
return *this;
}
int OSize() const
{
return m_times.size();
}
int Size() const
{
return m_occupied.size();
}
};
int main ()
{
ArrayTimes a1(600);
ArrayTimes a2(300);
a2[3] = 9;
a1 = a2;
std::cout << "Size: " << a1.OSize() << ", " << a1.Size() << std::endl;
std::cout << "Element: " << a1[3] << std::endl; // copied value from a2
return 0;
}
I managed to shrink the array to few elements, so there is no need of this tricky class.
Thanks for pointing out my mistakes, at least I learned something from this experience

Math ADD operation over vector of bools

So I created a class called myClass that takes in an int and has a private variable that stores the int as a vector in binary (i.e. 12 is '1100'). I want to define an operator that adds two myClass variables together as a vector of bools (aka bit-wise operation).
Here is the code I have:
class myClass {
public:
myClass();
myClass(int a);
myClass& operator+(const myClass& value);
private:
std::vector<bool> bit;
};
I want this to work in the main function:
int main() {
std::cin >> value;
Integer a = value;
std::cin >> value;
Integer b = value;
myClass c = a+b;
return 0;
}
Operator definition:
myClass myClass::operator+(const myClass& rhs) {
Integer c = // not sure what to do here
return c;
}
The part that's confusing me is that it must take in an integer but then the operator does the operation on the vector of bools.
Well obviously you need to do the same as when you add normal numbers on paper. Start with the lowest significance bits, and add them together. If the result overflows (eg. binary 1+1=10) then remember that overflow for the next iteration.
I'd strongly suggest that you first create constructor that takes bool array for your class:
myClass(std::vector<bool> bits);
We'll use that in the implementation. Now what you want is to add the lists of bools. I have created an implementation that doesn't care how big the lists are. This will be handy if you want to calculate with huge integers:
#include <vector>
bool add_bools(const bool A, const bool B) {
return !(A && B) && (A || B);
}
/** Loops over vectors and adds the booleans in them
the booleans are considered to be in little endian order
so that the least significant is first in the array. **/
std::vector<bool> add_vectors(const std::vector<bool>& first,
const std::vector<bool>& second) {
std::vector<bool> result;
// Remembers that previous addition produced false when
// we add true+true
bool overflow = false;
const int bits = first.size()>second.size()?first.size():second.size();
for (int i = 0; i < bits || overflow; ++i) {
bool bitA, bitB;
bitA = i<first.size() ? first[i]:false;
bitB = i<second.size() ? second[i]:false;
bool tmp_result = add_bools(bitA, bitB);
// remember to add overflow from previous iteration
result.push_back(add_bools(tmp_result, overflow));
// remember overflow for next iteration
overflow = (bitA&&bitB) || (overflow && tmp_result);
}
return result;
}
#include <iostream>
void test_add_vectors() {
std::vector<bool> first;
std::vector<bool> second;
const int bits = 5;
for (int i = 0, l = bits; i < l; ++i) {
first.push_back(false);
second.push_back(true);
}
first[0] = true;
std::vector<bool> result = add_vectors(first, second);
for (int i = 0, l = result.size(); i < l; ++i) {
std::cout<< (result[i]?'1':'0')<<" ";
}
}
You can use that implementation like this, making use of the constructor that takes bool array:
myClass myClass::operator+(const myClass& rhs) {
myClass result(add_vectors(bit, rhs.bit));
return result;
}
You need to define a way to go to and from an integer representation. Here's a rough idea:
#include <vector>
#include <iostream>
class myClass {
private:
void setInt(int x) {
bit.clear();
while (x) {
if (x & 1)
bit.push_back(1);
else
bit.push_back(0);
x>>=1;
}
reverse(bit.begin(), bit.end());
}
public:
int toInt() const {
int i = 0;
for (size_t b = 0; b < bit.size(); b++) {
if (bit[bit.size() - 1 - b])
i |= 1<<b;
}
return i;
}
myClass(int a) {
setInt(a);
}
myClass& operator+(const myClass& value) {
setInt(toInt() + value.toInt());
return *this;
}
private:
std::vector<bool> bit;
};
int main() {
myClass c(10);
myClass d(20);
std::cout << "c=" << c.toInt() << "\n";
std::cout << "d=" << d.toInt() << "\n";
std::cout << "Sum=" << (c + d).toInt() << "\n";
}
`myClass c = a+b;`
Since a and b are both declared as Integer, this line will call operator+(const Integer& x, const Integer& y) or Integer::operator+(const Integer& x). The only way it will call myClass::operator+(const myClass& rhs) is if you have a conversion constructor myClass::myClass(const Integer& i).

C++ Use Function Preconditions Or Wrapper Classes with Invariants?

I find myself writing a lot of functions that begin with many preconditions, and then I have to figure out how to handle all the invalid inputs and write tests for them.
Note that the codebase I work in does not allow throwing exceptions, in case that becomes relevant in this question.
I am wondering if there is any C++ design pattern where instead of having preconditions, input arguments are passed via wrapper classes that guarantee invariants. For example suppose I want a function to return the max value in a vector of ints. Normally I would do something like this:
// Return value indicates failure.
int MaxValue(const std::vector<int>& vec, int* max_value) {
if (vec.empty()) {
return EXIT_FAILURE;
}
*max_value = vec[0];
for (int element : vec) {
if (element > *max_value) {
*max_value = element;
}
}
return EXIT_SUCCESS;
}
But I am wondering if there is a design pattern to do something like this:
template <class T>
class NonEmptyVectorWrapper {
public:
static std::unique_ptr<NonEmptyVectorWrapper>
Create(const std::vector<T>& non_empty_vector) {
if (non_empty_vector.empty()) {
return std::unique_ptr<NonEmptyVectorWrapper>(nullptr);
}
return std::unique_ptr<NonEmptyVectorWrapper>(
new NonEmptyVectorWrapper(non_empty_vector));
}
const std::vector<T>& vector() const {
return non_empty_vector_;
}
private:
// Could implement move constructor/factory for efficiency.
NonEmptyVectorWrapper(const std::vector<T>& non_empty_vector)
: non_empty_vector_(non_empty_vector) {}
const std::vector<T> non_empty_vector_;
};
int MaxValue(const NonEmptyVectorWrapper<int>& vec_wrapper) {
const std::vector<int>& non_empty_vec = vec_wrapper.vector();
int max_value = non_empty_vec[0];
for (int element : non_empty_vec) {
if (element > max_value) {
max_value = element;
}
}
return max_value;
}
The main pro here is that you avoid unnecessary error handling in the function. A more complicated example where this could be useful:
// Finds the value in maybe_empty_vec which is closest to integer n.
// Return value indicates failure.
int GetValueClosestToInt(
const std::vector<int>& maybe_empty_vec,
int n,
int* closest_val);
std::vector<int> vector = GetRandomNonEmptyVector();
for (int i = 0; i < 10000; i++) {
int closest_val;
int success = GetValueClosestToInt(vector, i, &closest_val);
if (success) {
std::cout << closest_val;
} else {
// This never happens but we should handle it.
}
}
which wastefully checks that the vector is non-empty each time and checks for failure, versus
// Returns the value in the wrapped vector closest to n.
int GetValueClosestToInt(
const NonEmptyVectorWrapper& non_empty_vector_wrapper,
int n);
std::unique_ptr<NonEmptyVectorWrapper> non_empty_vector_wrapper =
NonEmptyVectorWrapper::Create(GetRandomNonEmptyVector());
for (int i = 0; i < 10000; i++) {
std::cout << GetValueClosestToInt(*non_empty_vector_wrapper, i);
}
which can't fail and gets rid of the needless input checking.
Is this design pattern a good idea, is there a better way to do it, and is there a name for it?

Returning a class object based on two variables C++

I need help with a problem pertaining to classes. I know how to solve it but I am wondering if there is a better solution than my current idea.
Each Class Tile Object and Class Player Object has an x and y position. I would like to know if there is a way to expedite things. My current idea is if-else statements like this:
if(x==1) {
if(y==1) {
return tileone1;
} else if(y==2) {
return tileone2;
} else if(y==3) {
return tileone3;
} else if(y==4) {
return tileone4;
} else if(y==5) {
return tileone5;
} //......
} else if(x==2) {
if(y==1) {
return tiletwo1;
} else if(y==2) {
return tiletwo2;
} else if(y==3) {
return tiletwo3;
} else if(y==4) {
return tiletwo4;
} else if(y==5) {
return tiletwo5;
} //......
} //......
The problem is it would take way too long to write this for every tile.
I need a function that will return a Tile object based on the x and y input of the Object Player. Any other solution would be great as well.
Tile getTileBasedOnCoords(int x, int y){
}
There are multiple ways to achieve this. The easiest seems to be (given the question) is by putting all Tile objects into the array, and returning the one with corresponding index.
Use a map with custom keys providing x and y values. This way you have direct access to the tile without the need to compare each tile with the player position (see getSectorByCoordinate() in the following code taken from a project of mine).
struct CSectorCoordinate
{
private:
int mX;
int mY;
public:
CSectorCoordinate();
CSectorCoordinate(int aX, int aY);
bool operator() (const CSectorCoordinate & a, const CSectorCoordinate & b) const;
int getX();
int getY();
};
...
bool CSectorCoordinate::operator() (const CSectorCoordinate & a, const CSectorCoordinate & b) const
{
// note: the following conditions ensure a strict weak ordering (see documentation of std::map)
if (a.mX < b.mX)
return true;
if (b.mX < a.mX)
return false;
return a.mY < b.mY;
}
...
typedef std::map<CSectorCoordinate, Configuration::CSectorEntity *, CSectorCoordinate> CSectorCoordinateMap;
CSectorCoordinateMap mSectorCoordinateMap;
...
bool CSectorEntityConfigurationBunch::getSectorByCoordinate(int aX, int aY, Configuration::CSectorEntity * & prSector)
{
CSectorCoordinateMap::const_iterator i(mSectorCoordinateMap.find(CSectorCoordinate(aX, aY)));
if (i != mSectorCoordinateMap.end())
prSector = i->second;
else
prSector = 0;
return prSector;
}

Assign value using overloaded subscript operator

I am trying to create custom array indexed from 1 using subscript operator. Getting value works fine, but I have no clue, why assign using subscript operator doesn't work.
class CEntry {
public:
CKey key;
CValue val;
CEntry(const CKey& key, const CValue& val) {
this->key = key;
this->val = val;
}
CEntry& operator= (const CEntry& b) {
*this = b;
return *this;
};
};
...
class EntriesArray {
public:
CEntry **entries;
int length;
EntriesArray(int length) {
this->length = length;
entries = new CEntry*[length];
int i;
for (i = 0; i < length + 1; i++) {
entries[i] = NULL;
}
};
CEntry& operator[] (const int index) {
if (index < 1 || index > length) {
throw ArrayOutOfBounds();
}
return *entries[index - 1];
};
};
Constructs array this way
EntriesArray a(5);
This works
a.entries[0] = new CEntry(CKey(1), CValue(1));
cout << a[1].val.value << endl;
This doesn't work
a[1] = new CEntry(CKey(1), CValue(1));
EDIT:
Using
CEntry *operator=( CEntry *orig)
it compiles okey, but gdb stops at
No memory available to program now: unsafe to call malloc warning: Unable to restore previously selected frame
with backtrace
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00007fff5f3ffff8
0x00000001000013c8 in CEntry::operator= (this=0x0, orig=0x1001008d0) at /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp:20
20 /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp: No such file or directory.
in /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp
At first... This:
CEntry& operator= (const CEntry& b) {
*this = b;
return *this;
};
Shouldn't work (this should result in recursive call of operator=).
The second thing is that you're trying to assign CEntry * to CEntry, this would work if you had CEntry *operator=( CEntry *orig), but I think this is bad coding practice.
This question may be related to this one.
I tried to fix your code; I believe that this is what you were trying to do:
(tested this code on g++ 5.3.0)
#include <iostream>
#include <stdexcept>
#include <string>
// Some implementation for CKey and CValue:
typedef int CKey;
struct CValue {
int value;
CValue(int value=0) : value(value) {}
};
class CEntry {
public:
CKey key;
CValue val;
CEntry(): key(0), val(0) {}
CEntry(const CKey& key, const CValue& val): key(key), val(val) {}
CEntry& operator= (const CEntry& b) {
this->key = b.key;
this->val = b.val;
return *this;
};
};
class EntriesArray {
public:
CEntry *entries;
int length;
EntriesArray(int length) {
this->length = length;
entries = new CEntry[length];
};
CEntry& operator[] (const int index) {
if (index < 1 || index > length) {
throw std::domain_error("out of bounds!");
}
return entries[index - 1];
};
};
int main(int argc, char* argv[]) {
using namespace std;
EntriesArray a(5);
// This works
a.entries[0] = CEntry(CKey(1), CValue(1));
cout << a[1].val.value << endl;
// This doesn't work
a[1] = CEntry(CKey(2), CValue(2));
cout << a[1].val.value << endl;
}
Also you might want to use a[1] as a[1].val.value e.g.:
cout << a[1] << endl;
To do this just add to this line to cEntry:
operator int() { return val.value; }
I hope it helps.
You could try replacing
CEntry& operator[] (const int index) {
if (index < 1 || index > length) {
throw ArrayOutOfBounds();
}
return *entries[index - 1];
};
with
void Add(const int index, CEntry *pEntry) {
if (index < 1 || index > length) {
throw ArrayOutOfBounds();
}
entries[index - 1] = pEntry;
};
but since you are now storing references to objects allocated on the heap (with new) you will need a destructor ~EntriesArray() to delete them all.
Because EntriesArray::operator[] returns a CEntry &, but new CEntry returns a CEntry *.
Perhaps you want a[1] = CEntry(CKey(1), CValue(1))? (no new.)
By the way, your current definition of CEntry::operator= will lead to a stack overflow.
This
return *entries[index - 1];
dereferences a NULL pointer.
You want the pointer itself to be overwritten by a[1] = new CEntry(CKey(1), CValue(1));, not the pointed-to-value.
Try this:
class EntriesArray
{
public:
int length;
CEntry **entries;
EntriesArray( int length ) : length(length), entries(new CEntry*[length]())
{
}
// defaulted special member functions are inappropriate for this class
EntriesArray( const EntriesArray& ); // need custom copy-constructor
~EntriesArray(); // need custom destructor
EntriesArray& operator=(const EntriesArray&); // need custom assignment-operator
CEntry*& operator[] (const int index) {
if (index < 1 || index > length) {
throw ArrayOutOfBounds();
}
return entries[index - 1];
}
};
Further to my comment above:
To make it work with writing new values, you probably need something like this
(I haven't double checked for off by one or ptr vs reference stuff)
CEntry& operator[] (const int index) {
if (index < 1) {
throw ArrayOutOfBounds();
}
// Add default elements between the current end of the list and the
// non existent entry we just selected.
//
for(int i = length; i < index; i++)
{
// BUG is here.
// We don't actually know how "entries" was allocated, so we can't
// assume we can just add to it.
// We'd need to try to resize entries before coming into this loop.
// (anyone remember realloc()? ;-)
entries[i] = new CEntry();
}
return *entries[index - 1];
};