Order of elements in set of pointers - c++

Why does the following code get compiled even though I have commented the A::operator<. I wonder how the output of the following code is printed in ascending order without the < operator. How can I change the order to descending? (note: this code does not get compiled if I use A instead of A* unless I provide a definition for A::operator<)
#include <iostream>
#include <set>
using namespace std;
class A
{
public:
A(int v):x(v){}
virtual ~A(){}
int x;
/*bool operator<(const A &a) const
{
return x > a.x;
}*/
};
int main()
{
set<A*> numbers;
A* a1 = new A(1);
A* a2 = new A(2);
A* a3 = new A(3);
numbers.insert(a2);
numbers.insert(a3);
numbers.insert(a1);
for(set<A*>::iterator itr = numbers.begin();itr!=numbers.end();itr++)
{
cout << (*itr)->x << endl;
}
// output: 1 2 3
return 0;
}

Your code gets compiled because you have a set of pointers. Since the set contains pointers, and your operator does not compare pointers, but rather, objects of type A, it is not needed for the set. There is an existing pointer less-than comparison operator, which is what gets used in your set.
You can change the ordering by providing your own comparator implementing strict weak ordering:
struct APtrComp
{
bool operator()(const A* lhs, const A* rhs) const { /* implement logic here */ }
};
And instantiate your set using it as second template parameter.
set<A*, APtrComp> numbers;

you have a set of pointers. usually pointers are allocated in increasing order. and pointers have a default < operator. so this is why it's compiling and working.
P.s. it will print you the value of A1 A2 A3 in this order no matter what's there values:
...
A* a1 = new A(9);
A* a2 = new A(5);
A* a3 = new A(1);
...
// output: 9 5 1

If you remember your pointer arithmetic, all points are given a set of operators to use in operations(which includes the operator<). Your set will use this default operator < .

From what I understand you want to know why the code compiles with A* even if you dont have the operator< and how to change the order from ascending to descending.
It compiles because it is using the operator< with the pointers address.
change cout << (*itr)->x << endl;
to cout << (*itr)->x << ' ' << *itr << endl; and you'll see it easily :)
It is normal that the code doesn't compile without the operator< if you're using the set<A>. It won't know what to compare in order to insert the members sorted. So you have to provide that operator!
If you want to keep using pointers, you can use the code provided by #juanchopanza.

Related

best practice to select and modify entries in nested vectors

I'm looking for an efficient way to solve the following (presumably easy) problem:
I have a vector of type A.
Class A contains a vector of type B.
There is no way that I can change class A or the design of
the vector of class A (I cannot make it a vector of pointers to A
for example).
I want to have a vector of class B which contains all entries of B contained in the vector of A with a special attribute.
I guess it is a bit complicated to read about the problem but probably easier to understand if you see an example:
#include <vector>
#include <iostream>
using namespace std;
struct B {
int n;
double val;
};
struct A {
vector<B> v;
};
int main() {
// generate some dummy data:
A a1;
a1.v.push_back(B{1, 1.0});
a1.v.push_back(B{2, 2.0});
a1.v.push_back(B{1, 3.5});
A a2;
a1.v.push_back(B{2, 2.0});
a1.v.push_back(B{3, 1.0});
a1.v.push_back(B{1, 2.5});
// this is my initial situation: a vector of type A
vector<A> va;
va.push_back(a1);
va.push_back(a2);
// what I want to get is a vector of type B with all B values whose n == 1
vector<B> vb;
// possible solution to get all elements of B
for(auto &any : va){
for(auto &b : any.v){
if(b.n == 1){
vb.push_back(b);
}
}
}
for(const auto &any:vb){
cout << any.val << endl;
}
return 0;
}
Questions:
I would like to get the vector of class B without copying every element. Later, I need to modify the elements in vector B and they should also be modified in vector A (meaning, if I change vb[0].val = 100; the entry in va[0].v[0] should also be 100;
I thought about using pointers to do this but I am unsure if it is a good idea since the elements of vector va are allocated on the stack and not on the heap.
** Edit: **
I can ensure that as soon as I need the vector of B I will not modify the vector of A in any way.
Having va on the stack is not necessarily a problem, as long as you move va to its new location. In that case your "moved to" vector will internally point to the storage allocated by your "moved from" va vector (and the original va will become empty).
What is an issue though, is if you add new Bs to an A after having already created pointers to Bs. If the A's v vector does not have enough capacity to store the newly inserted B, it will have to reallocate all its B elements to a new storage location. That in turn will change the addresses of all of those B elements.
Thus, you are fine to create pointers as long as you can guarantee that:
va is moved instead of copied.
No new Bs are added to an A after initialization.
Assuming the above can be guaranteed, you can create your vb as follows:
std::vector<B *> vb;
for (auto & a : va) {
for (auto & b : a.v) {
if (b.n == 1) { vb.push_back(&b); }
}
}
or using std::reference_wrapper:
std::vector<std::reference_wrapper<B>> vb;
for (auto & a : va) {
std::copy_if(a.v.begin(), a.v.end(),
std::back_inserter(vb),
[](auto const & b) { return b.n == 1; });
}

Exploiting fact that elements of vector are stored in heap?

Lets say you have something like this
#include <iostream>
#include <vector>
using namespace std;
vector<int> test()
{
vector <int> x(1000);
for (int i = 0; i < 1000; i++)
{
x[i] = 12345;
}
return x;
}
int main(int argc, const char * argv[])
{
vector<int> a = test();
return 0;
}
where within a function you create a vector and fill it with some elements (in this case I chose 12345 but they won't necessarily all be the same).
I have read that the elements of the vector are stored on the heap whereas the reference and header data are stored on the stack. In the above code, when x is returned a copy-constructor must be called, and this takes O(n) time to copy all the elements into a new vector.
However, is it possible to take advantage of the fact that all the elements already exist on the heap in order to just return something like a pointer to those elements and later just create a vector that uses that pointer in order to point to those exact same elements — thus avoiding the need to make a copy all the elements of a vector?
The compiler does this for you, freeing you up to write nice , easy-to-read code, rather than mangling your code for the sake of optimization.
When you return a value for a function, the compiler is allowed to elide the return value object. The net effect is that the compiler can just create x in the actual memory location of a.
Even if it doesn't do this (e.g. it chooses not to for some reason, or you disable it by a compiler switch), then there is still the possibility of a move.
When a move happens, the vector will just transfer ownership of the pointer from x to the return value, and then from the return value to a. This leaves x etc. as an empty vector, which is then correctly destroyed.
You could explore this by writing a test class (instead of vector<int>) which prints something out for its default constructor, copy-constructor, and move-constructor, e.g.
#include <iostream>
struct A
{
A() { std::cout << "default\n"; }
A(A const &) { std::cout << "copy\n"; }
A(A &&) { std::cout << "move\n"; }
};
A func() { A a; return a; }
int main()
{
A b (func());
}
Output with g++:
default
Output with g++ -fno-elide-constructors:
default
move
move

Deep copy of a matrix-like class

I've got a class that shall behave like matrix.
So the usecase is something like:
Matrix matrix(10,10);
matrix[0][0]=4;
//set the values for the rest of the matrix
cout<<matrix[1][2]<<endl;
code:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <sstream>
using namespace std;
class Matrix {
public:
Matrix(int x, int y);
class Proxy {
public:
Proxy(int* _array) : _array(_array) {
}
int &operator[](int index) const {
return _array[index];
}
private:
int* _array;
};
Proxy operator[](int index) const {
return Proxy(_arrayofarrays[index]);
}
Proxy operator[](int index) {
return Proxy(_arrayofarrays[index]);
}
const Matrix& operator=(const Matrix& othersales);
private:
int** _arrayofarrays;
int x, y;
};
Matrix::Matrix(int x, int y) {
_arrayofarrays = new int*[x];
for (int i = 0; i < x; ++i)
_arrayofarrays[i] = new int[y];
}
const Matrix& Matrix::operator=(const Matrix& othermatrix) {
new (this) Matrix(x, y);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
_arrayofarrays[i][j] = othermatrix._arrayofarrays[i][j];
return *this;
}
int main() {
Matrix a(2, 3);
a[0][0] = 1;
a[0][1] = 2;
a[0][2] = 3;
a[1][0] = 4;
a[1][1] = 5;
a[1][2] = 6;
cout << a[1][2] << endl;
//prints out 6
const Matrix b = a;
cout << b[1][2] << endl;
a[1][2] = 3;
cout << a[1][2] << endl;
// prints out 3
cout << b[1][2] << endl;
// prints out 3 as well
}
By calling const Matrix b = a; I want to create new instance of Matrix, that will have the same values as a has in that moment. Nevertheless b is being affected by changing the values in a. So if I change some value in a, then it changes in b as well. And I don't want it to behave like this.
So I need to create a copy of b that would not be affected by a itself.
Those might be stupid question, but for me, as a java guy and a C++ newbie are all those stuff really confusing, so thanks for any helpful advices...
There are a few issues with your implementation. The simple one is the error you are getting...
In your Matrix class, operator[] is a non-const member function, which means that it can only be executed on non-const objects. Your operator= takes the right hand side object by const &, and thus you cannot call operator[] on it. The issue here is that you are not offering an implementation of operator[] that promises not to modify the object, once you add that to your type it should compile.
More important than that is the fact that you are leaking memory. When you call operator= on an object you are creating a different Matrix in place, without previously releasing the memory that it held. That is a memory leak.
The implementation of operator= is also not thread-safe. If allocation of memory for any of the internal arrays fails and throws an exception you are leaving your object in a state that is neither the original one nor a valid state. This is bad in itself.
Related to the previous, in as much as correcting one probably leads to the other, your implementation of operator= is not safe if there is aliasing, that is, it fails if you self-assign. The first line will leak the memory and create the new buffers, and from there on you will copy the new buffer into itself, loosing the original information.
Finally, the implementation of the type could be improved if you drop the requirement of using operator[] and use instead operator() with the two indices. User code will have to be adapted (and look less like a bidimensional array) but it provides a bit more freedom of representation (you can store the information internally in any way you want). At the same time, there is no need to allocate an array of pointers and then N arrays of int. You can perform a single memory allocation of NxM ints and do pointer arithmetic to address each location (this is independent of the use of operator[]/operator()), which will reduce the memory footprint and make the layout more compact, improving cache performance (not to mention reducing the number of dynamic allocations by a factor of M)
By calling const Matrix b = a; I want to create new instance of Matrix, that will have the same values of a in that moment. Nevertheless b is being affected by changing the values in a.
Well, this is yet another issue I missed in the first read. The expression const Matrix b = a; does not involve operator=, but rather the copy constructor. Another thing to google: Rule of the Three (basically, if you implement one of copy-constructor, assignment or destructor manually, you probably want to implement all three). Without defining your own copy constructor the compiler will implicitly define one for you that does a shallow copy (i.e. copies the pointers stored in Matrix but does not allocate memory for it). After the copy is made both Matrix share the same memory, and if your destructor releases the memory, you will run into Undefined Behavior when the second destructor runs and tries to delete [] the already deleted memory.

Overload operator '+' to add two arrays in C++

I want to add two arrays by simply writing:
int a[4] = {1,2,3,4};
int b[4] = {2,1,3,1};
int sum[4] = a + b;
I wrote this function but I got an error
int* operator+(const uint32& other) const{
uint32 sum[n];
for(int i=0; i<n; i++){
sum[i] = (*this[i]) + other[i];
}
return sum;
}
Could you help me on this? Thanks in advance.
Let's go through your code, piece by piece, and look at the problems:
int* operator+(const uint32& other) const{
You can't overload operators for built-in types, so this is doomed from the beginning
Even if you could do this (which you can't), it needs to take two parameters since it's non-member binary function.
uint32 sum[n];
You can't make variable-length arrays in C++ (assuming n isn't a compile-time constant) (note: G++ has some extensions that allow this, but it's non-standard C++)
for(int i=0; i<n; i++){
sum[i] = (*this[i]) + other[i];
There's no this pointer to begin with in this code (it's not a member function)...
const uint32& other is not an array/pointer to an array. It's a single reference to a single uint32. That means that other in this code is not an array/pointer to an array, and so you cannot do other[i] (it's like trying to do int x = 3; x[4] = 13;, which makes no sense).
}
return sum;
You're returning a pointer to a locally allocated array, which means this will result in undefined behavior, as the memory associated with sum is going to get annihilated when this function returns.
}
This is probably wrong, but it appears to work (C++11):
#include <iostream>
#include <array>
using namespace std;
template <class T>
T operator+(const T& a1, const T& a2)
{
T a;
for (typename T::size_type i = 0; i < a1.size(); i++)
a[i] = a1[i] + a2[i];
return a;
}
int main()
{
array<int,5> a1 = { 1, 2, 3, 4, 5 };
array<int,5> a2 = { 2, 3, 4, 5, 6 };
array<int,5> a3 = a1 + a2;
for (int i = 0; i < 5; i++)
cout << a1[i] << '+' << a2[i] << '=' << a3[i] << ' ';
cout << endl;
return 0;
}
Output (ideone):
1+2=3 2+3=5 3+4=7 4+5=9 5+6=11
I think the issue is that you're missing a way to pass in the length of the array. You might need to do something a bit more sophisticated. Something like:
class AddingVector : public std::vector<int>
{
public:
typedef AddingVector type;
type operator+(const AddingVector& rhs, const AddingVector& lhs)
{
/* validate that they're the same size, decide how you want to handle that*/
AddingVector retVal;
AddingVector::const_iterator rIter = rhs.begin();
AddingVector::const_iterator lIter = lhs.begin();
while (rIter != rhs.end() && lIter != lhs.end()) {
retVal.push_back(*rIter + *lIter);
++rIter;
++lIter;
}
return retVal;
}
}
You cannot do that. Non-member binary operators must take two arguments (you only provided one), so you could try this:
int* operator+(const uint32& a, const uint32& b)
But that can't possibly work either, since you want to add arrays, not single uint32 variables. So you would think that this would do it:
int* operator+(const uint32[] a, const uint32[] b)
or:
int* operator+(const uint32[4] a, const uint32[4] b)
But no go. It's illegal because you cannot have pointer types as both arguments in an operator overload. Additionally, at least one of the arguments must be a class type or an enum. So what you're trying to do is already impossible on at least two different levels.
It's impossible to do what you want. One correct way to go about it is to write your own class for an array that can be added to another one.
You cannot overload operators for types other than your own defined types. That is, if you create a class X, you can overload operators for X, but you cannot overload operators for arrays or pointers to fundamental types.
first is your code getting compiled properly, you have used 'n' directly in declaring array, is 'n' declared as constant..
And moreover you have taken a local variable in the function and returning it, well, this return a garbage form the stack, wat i can suggest is you malloc some memory and use it,, but again freeing it would be needed...
Hey, what you could do is,
Take a wrapper class "array"
class array
{
int *ipArr;
DWORD size;
};
then in constructor you can pass the size you want to have an array of
array(DWORD dwSize);
{
// then malloc memory of size dwSize;
}
Have an overloaded operator'+' for this class, that will have the above implementation of adding two int arrays,
Note here you will also need to overlaod the '=' assignment operator, so that our array class can you is directly..
now you can free the associated memory in the destructor
You have a few problems. The first is that you aren't passing in both arrays, and then you don't specify what n is, and the last is that you are trying to pass out a pointer to a local variable. It looks like you are trying to make a member operator of a class.
So basically you are trying to add the contents of an unspecified length array to an uninitialised array of the same length and return the stack memory.
So if you pass in pointers to the arrays and the length of the array and an output array then it would work, but you wouldn't have the syntax
sum = a + b;
it would be something like
addArray(&a, &b, &sum, 4);
To get the syntax you want you could make a class that wraps an array. But that is a much more complicated task.

Creating an array of classes not working

I'm trying to create an array of classes using a vector, but I think I'm getting the syntax wrong from instantiating the array. The error I'm getting is:
error: request for member 'setX' in objects[0], which is of non-class type 'std::vector'
#include <iostream>
#include <vector>
using std::cout;
class A {
public:
void setX(int a) { x = a; }
int getX() { return x; }
private:
int x;
};
int main() {
std::vector<A> *objects[1];
objects[0].setX(5);
objects[1].setX(6);
cout << "object[0].getX() = " << objects[0].getX() << "\nobject[1].getX() = " << objects[1].getX() << std::endl;
}
std::vector<A> objects; // declare a vector of objects of type A
objects.push_back(A()); // add one object of type A to that vector
objects[0].setX(5); // call method on the first element of the vector
With an asterisk and a square brackets, you are declaring an array of pointers to vectors instead of a vector. With std::vector<T> you do not need square brackets or an asterisk:
std::vector<A> objects(2); // 2 is the number of elements; Valid indexes are 0..1, 2 is excluded
objects[0].setX(5); // This will work
objects[1].setX(6);
The reason the compiler thought that you were trying to call setX on a vector is that the square bracket operator, overloaded by the vector, is also a valid operator on an array or a pointer.
An array and std::vector are two completely different container types. An array is actually a fixed-size block of memory, where-as a std:vector object is a dynamic sequential container type, meaning it can be dynamically "grown" and "shrunk" at run-time, and the object itself manages the memory allocation of the objects it owns. Their apparent similarities are that both can access members in O(1) complexity and can use the bracket syntax for accessing members.
What you want is something like the following:
int main()
{
//make a call to the std::vector<T> cstor to create a vector that contains
//two objects of type A
std::vector<A> objects(2);
//you can now access those objects in the std::vector through bracket-syntax
objects[0].setX(5);
objects[1].setX(6);
cout << "object[0].getX() = " << objects[0].getX() << "\nobject[1].getX() = " << objects[1].getX() << std::endl;
return 0;
}
here what you did is define an array with 1 element of type std::vector*, you may want to read more about vector and array first.
The correct way to define it is:
std::vector<A> objects(2);
or using pointers if that is what you intend to
std::vector<A*> objects(2);
objects[0] = new A();
objects[1] = new A();