C++ std::valarray member variable unexpected change - c++

I have a class A whose constructor takes as one of its arguments as an std::valarray[^1], however I have found that its values change to large random numbers once the constructor has finished.
As an aside, there could be an issue with my getters and setters, which I just started using in the cotext of C++ with the help of this SO question and 18.3.5 Accessor Functions from Stroustrup's The C++ Programming Language.
Stroustrup's format of constexpr double real() const { return re; } is what my example ended up using, however without constexpr since my class didn't like it (I'm trying to understand why but still haven't got it yet).
A comment on the accepted answer of my question by user deidei says that std::valarray is "dynamic", which I guess here means that you can resize it. That might bring issues when it comes to memory, and I think that my values might have been overwritten somehow due to this fact.
#include <iostream>
#include <valarray>
#include <vector>
class A
{
public:
A(std::valarray<int> b, std::vector<int> c)
{
std::cout<< b[0] << std::endl;
};
std::valarray<int> get_b() const {return b;};
std::vector<int> get_c() const {return c;};
private:
std::valarray<int> b;
std::vector<int> c;
};
int main()
{
std::valarray<int> b = {1, 3};
std::vector<int> c = {4, 2, 8, 17};
A a(b,c);
std::cout<< a.get_b()[0] << std::endl; // returns a random large number such as 26618992
return 0;
}
What issue might be causing this problem?
[^1]: (inspired by the answer to my previous question, for those of you playing along at home)

My understanding was that since the constructor takes b and c as
arguments then they will be assigned to member variables of the same
name
This is incorrect. You can initialize member variable via member initializer list, via default initialization or by assigning values directly in the body of constructor. For example:
A(std::valarray<int> b, std::vector<int> c)
: b(b), c(c)
{...
or
private:
std::valarray<int> b = {1, 3};
std::vector<int> c = {4, 2, 8, 17};
or
A(std::valarray<int> b, std::vector<int> c)
{
this->b = b;
this->c = c;
...
You have done none of the above, so your valaray of int's is size of 0. When you return its copy and trying to access non-existing element
// returns a random large number such as 26618992
you get some garbage value from the memory.

Related

C++ assigning data to array like initialization

Why we can initialize array with
int a[]={1,2,3};
but we can't assign data to existing array
a = {2,3,4};
?
Is it possible to make a function that takes const array as a parameter, and call it to assign variable in one line?
pseudocode:
int a[] = {1,2,3};
myfunc(a, (int){2,3,4});
void myfunc(int &array1, const int array2)
{
copy(array2,array1);
}
Since C-array can't do that.
C-array doesn't have assignment operator available.
Reason is purely historical. First of all memory at that time was very limited. Creating a feature to easy copy of array was considered as a waist of memory and time so it was not a priority. In fact it was more important to ensure that arrays are passed by pointer (not by value), that is why array in C and C++ decay to pointer to value. Also most of other languages of that time didn't had such capability. Later the backward comparability took over and such feature was never introduced.
Use more modern std::array where this is possible.
std::array<int, 4> a { 1, 3, 4, -2 };
a = { -4, -2, 0, 0 };
https://wandbox.org/permlink/PLeISvwWd8WtfZ3L
Yes, you can write a function-template that deduces the size of the arrays
template<size_t N>
void myfunc(int (&a)[N], int const (&b)[N])
{
std::copy(b, b + N, a);
}
Note that this allows the second parameter to be deduced from a brace-init list as you want. An additional advantage is that you can't get the sizes wrong.
Now you can copy in a single line
int main()
{
int a[] = {1,2,3};
for (auto i : a)
std::cout << i; // 1 2 3
myfunc(a, {2,3,4});
for (auto i : a)
std::cout << i; // 2 3 4
myfunc(a, {2,3,4,5}); // error, as it should be
}

GTEST: False negative for incorrect number of macro arguments

I have a class A for which I've overloaded the operator[] such that if object a of class A can have an std::valarray passed to it in the following manner:
std::valarray<int> in{2,1};
auto b = a[in]; // lets say this returns an int k = 2
auto c = a[{2,1}]; // also returns an int k = 2
However, when using the GTEST framework, it doesn't like the a[{2,1}] notation, and complains that macro "EXPECT_EQ" passed 3 arguments, but takes just 2 if we are to try a test such as EXPECT_EQ(2, a[{2,1}]);
Surely a[{2,1}] is a single argument, since it evaluates to an int? This doesn't seem to be the case. A typical EXPECT_EQ such as EXPECT_EQ(2, 2); is just fine.
Below, I have a MWE of a class that overloads [] to takes a parameter of type std::valarray.
class A
{
private:
std::vector<int> elems;
public:
A(std::vector<int> elems)
: elems(elems){};
int operator[](std::valarray<int> idx) const
{
return get_elem(idx[0]);
}; // getter
int get_elem(int idx) const {return this->elems[idx];}; //getter
int &get_elem(int idx) {return this->elems[idx];}; //setter
};
int main()
{
std::vector<int> elems = {2, 5, 0, 9,
5, 1, 4, 6};
A a(elems);
std::cout<< "hello world" << std::endl;
std::valarray<int> in{2,1};
auto b = a[in]; // lets say this returns an int k = 2
auto c = a[{2,1}]; // also returns an int k = 2
std::cout<< b << std::endl;
std::cout<< c << std::endl;
return 0;
}
Given that my main() displays correct behaviour, I suspect that there is an issue with GTEST, or is evaluation order in C++ different from what I expect?
Since macros are involved, and there is no getting rid of them, the quickest solution is a judicious use of parentheses:
EXPECT_EQ(2, ( a[{2,1}] ));
The extra pair will prevent the comma from being interpreted as an argument separator for the macro. As for the comparison itself, a parenthesized expression has the exact same value and value-category as the expression withing the parentheses. So everything should still work1.
1 - Unless Google Test applies decltype to that second sequence of tokens, then the extra parentheses can potentially cause surprises. But it shouldn't be doing that.

assign values to member of a struct with a for loop

I have a struct of the form
struct Thing {
std::vector<bool> A;
std::vector<int> B;
};
in the main the struct is created inside a for loop and used as the input to a function
for(int i=0;i<50;i++) {
Thing temporalthing;
temporalthing.A=A;
temporalthing.B=B;
temporalresult=fun1(temporalthing,data)
}
A and B are hardcoded into a series of vectors stored like this
std::vector<bool> A1{ 1,0,1};
std::vector<int> B1{ 2,1,3};
std::vector<bool> A2{ 0,1,1};
std::vector<int> B2{ 4,2,3}; ....
I want for each iteration of the for loop to take the corresponding value of A and B (loop 1 take A1 and B1, loop 2 take A2 and B2, ETC), if this were MATLAB this would be easy using reflection but I understand C++ does not have reflection, my other option would be to use a Switch Case structure of 50 different values that surely would work but I am not sure if this is the most optimal way to do it. Is there a better way?
I am new to C++ having a lot more experience with MATLAB but trying to learn... any help is very appreciated
My suggestion:
Change
temporalthing.A=A;
temporalthing.B=B;
to
temporalthing.A = getA(i);
temporalthing.B = getB(i);
The functions getA() and getB() can use whatever logic to return you an A and a B for the given i.
A simple implementation for getA() would be to store the various As in a vector.
std::vector<int>& getA(size_t i)
{
static std::vector<std::vector<int>> aList;
if ( aList.empty() )
{
// Fill up the list
aList[0] = {1, 0, 1};
aList[1] = {0, 1, 1};
// etc.
}
return aList[i];
}
Do the same thing for getB().
If getA() can use i to compute the return value, then, it does not have to store the As.
std::vector<int> getA(size_t i)
{
int v1 = func1(i);
int v2 = func2(i);
int v3 = func3(i);
return {v1, v2, v3};
}

Using for_each to modify std containers (even though you shouldn't)

I'm taking a self-study course for C++, learning how the Standard Library works, and I want to understand how this code that uses for_each works, particularly regarding mutating objects (as opposed to native data types). I realize that you shouldn't use for_each this way, but this is for the purpose of learning.
I had thought this code would mutate all the elements in the set, but it doesn't.
My question is: 1. Why doesn't this code mutate the set?
2. How can the code be altered so that it will modify the set? To clarify: is there a way to keep the for_each and have it manipulate the set, or is this not possible and some other method (such as transform) has to be used?
Code
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
class A {
int a;
public:
A(int a) : a(a) {}
int getA() const { return a; }
void setA(int a) { this->a = a; }
bool operator<(const A & b) const { return a<b.a; }
};
struct myprinter {
void operator()(const A & a) { cout << a.getA() << ", "; }
};
struct doubler {
void operator()(A a) { a.setA(a.getA()*2); }
};
int main() {
int mynumbers[] = {8, 9, 7, 6, 4, 1};
set<A> s1(mynumbers, mynumbers+6);
for_each(s1.begin(), s1.end(), doubler()); //<-- Line in question
for_each(s1.begin(), s1.end(), myprinter());
return 0;
}
//Expected output: 2, 8, 12, 14, 16, 18
//Actual output: 1, 4, 6, 7, 8, 9,
What I've tried so far
At first I thought the problem was that doubler was taking the parameter by value and not by reference, so it wasn't saving the changes to the set. But when I change the signature to be void operator()(A & a), I get the error of:
error: no match for call to '(doubler) (const A&)
' __f(*__first);
~~~^~~~~~~~~~
error: binding 'const A' to reference of type 'A&' discards qualifiers
I deducted that that line being pointed out is from the internal implementation of for_each. I cannot make the parameter a const ref, because I am trying to change the a value using the setA() method, so it cannot be const.
If I change the set to be a vector instead, then when I changed the signature of doubler to take a reference, it successfully doubled the elements in the container. Why would it not work if the container is a set instead?
Edit: moooeeeep linked to another question that shows how to edit each element of a set. This is a practical solution to my problem, but my question is more theoretical - why can you not edit sets using for_each, where you can edit vectors and other stl containers?
Because a std::set manages the order of it's elements, it prohibits the user to change it's elements through it's iterators. Which means it's begin() and end() methods return a const_iterator. You're only allowed to read the element pointed to by that iterator, not modify it (it's const) which is what doubler() is trying to do.
A solution would be to just use std::vector and std::sort to order it yourself:
#include <iostream>
#include <algorithm>
#include <vector>
class A {
int a;
public:
A(int a) : a(a) {}
int getA() const { return a; }
void setA(int a) { this->a = a; }
bool operator<(const A & b) const { return a<b.a; }
};
struct myprinter {
void operator()(const A & a) { cout << a.getA() << ", "; }
};
struct doubler {
void operator()(A& a) { a.setA(a.getA()*2); } // by reference!
};
int main() {
int mynumbers[] = {8, 9, 7, 6, 4, 1};
std::vector<A> s1(mynumbers, mynumbers+6);
std::sort(s1.begin(), s1.end());
std::for_each(s1.begin(), s1.end(), doubler());
std::for_each(s1.begin(), s1.end(), myprinter());
return 0;
}
The problem is that you are not allowed to modify elements in a std::set. If it were possible, then how would it handle something like this:
std::set<int> my_set { 1, 2, 3 };
int& foo = *(my_set.begin());
foo = 2;
Now there is two elements with value 2. That doesn't make sense in a set due to
std::set is an associative container that contains a sorted set of unique objects of type Key.
(emphasis mine)
http://en.cppreference.com/w/cpp/container/set
Because the contents of an object in an std::set determines its position. That's why std::set iterators are always const.
Of course, it is often the case that not all members of an object have an effect on its position. A possible workaround is then to declare those members mutable. Then you can modify them using const references.
To modify a member that does affect the object's position in a set, remove the object from the set, modify it, and add it back in.
Based on the comments, I've learned the following so far:
1. Why doesn't this code mutate the set?
Because the parameter passed into the doubler method is passed by value (the C++ default), instead of by reference. Therefore, the value of each a parameter is modified, but this is not saved to the element in the container.
2. How can the code be altered so that it will modify the set?
Not easy to do. Sets (as opposed to other containers such as vectors, deques, lists, and arrays) maintains order to its elements. (Suppose instead that the function used in the for_each method negated every element. Then the set would be ordered backwards, and the order the set tried to maintained would be lost). Thus, if you want to modify the elements of a set you have to do so one at a time (Thank you #NathanOliver and #moooeeeep for your comments)
Note: If the container was not a set (instead, a vector or deque), then the doubler method could be modified to the following to mutate the elements:
void operator()(A & a) { a.setA(a.getA()*2); }
You can't simply change the key of an element in a key-value store kind of a data structure. (In case of a set, it's only key, no value.)
If you would, the element's position in the underlying container might need to be adjusted, based on the recomputed hash value in case of an unordered hash table, or a different sorting position in a binary search tree / ordered list.
Therefore the API of the std::set requires you to erase and reinsert the item in this case.
Which the answers to existing questions in this direction already state:
C++ STL set update is tedious: I can't change an element in place
How to update an existing element of std::set?
This is a piece of cake with a lambda expression.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
int mynumbers[] = {8, 9, 7, 6, 4, 1};
vector<int> s1(mynumbers, mynumbers+6);
sort(s1.begin(), s1.end());
for_each(s1.begin(), s1.end(), [](int &x) { x*=2; });
for_each(s1.begin(), s1.end(), [](int x) { cout << x << ", "; });
return 0;
}
OUTPUT:
2, 8, 12, 14, 16, 18,
The doc for std::set (http://www.cplusplus.com/reference/set/set/) defines the std::set::iterator returned by non-const version of begin and end as :
a bidirectional iterator to const value_type
So, even non-const std::set::iterator returns a const object.
There is in fact nothing wrong with modifying elements in the functor of a for_each:
If InputIt is a mutable iterator, f may modify the elements of the range through the dereferenced iterator
So next we should look at the definition of set, note that since c++11 clarified this, both it's iterator and const_iterator types are: "Constant Bidirectional Iterators".
So it is undefined behavior to modify a set with a for_each.

std::array initializer list initialization in initialization list

Although I much enjoy the new features in C++11, sometimes I feel like I'm missing some of its subtleties.
Initializing the int array works fine, initializing the Element2 vector works fine, but initializing the Element2 array fails. I think the correct syntax should be the uncommented line, but none of the initialization attempts have succeeded for me.
#include <array>
#include <vector>
class Element2
{
public:
Element2(unsigned int Input) {}
Element2(Element2 const &Other) {}
};
class Test
{
public:
Test(void) :
Array{{4, 5, 6}},
Array2{4, 5},
//Array3{4, 5, 6}
Array3{{4, 5, 6}}
//Array3{{4}, {5}, {6}}
//Array3{{{4}, {5}, {6}}}
//Array3{Element2{4}, Element2{5}, Element2{6}}
//Array3{{Element2{4}, Element2{5}, Element2{6}}}
//Array3{{{Element2{4}}, {Element2{5}}, {Element2{6}}}}
{}
private:
std::array<int, 3> Array;
std::vector<Element2> Array2;
std::array<Element2, 3> Array3;
};
int main(int argc, char **argv)
{
Test();
return 0;
}
I've tried this on g++ 4.6.1 and 4.6.2 under MinGW.
How should I correctly go about initializing this array? Is it possible?
The correct way to go about this is Array{{4, 5, 6}}. You cannot omit braces when you initialize a member with aggregate initialization. The only time you can omit braces is in a declaration of the form
T t = { ... }
So in your case you have to type out all braces: One for the std::array itself, and one for the int array. For Array3, your syntax is correct too, since int can be converted to Element2 implicitly.
From the remaining commented ones, the Array3{{{4}, {5}, {6}}}, Array3{{Element2{4}, Element2{5}, Element2{6}}} and Array3{{{Element2{4}}, {Element2{5}}, {Element2{6}}}} work too, but are more wordy. However conceptionally the Array3{{{4}, {5}, {6}}} one produces the least amount of temporaries on implementations that don't do copy elision (I guess that's irrelevant, but still good to know), even less than the Array3{{4, 5, 6}} one, because instead of copy initialization you use copy list initialization for your Element2, which doesn't produce an intermediary temporary by design.