phoffric
asked on
C++ Valarray program compiler error using g++
The below program builds/runs OK in VS 2010 Express, but since we run on Linux, I moved it over. I get a compiler error using g++ version 4.8.2. Not sure what I have to do to get the program to run on Linux. (BTW, my project does not use C++11.)
#include <valarray>
using namespace std;
void foo(valarray<int>& va)
{
slice_array<int>& sa = va[slice(0,3,2)];
sa = 98;
}
int main()
{
valarray<int> valary(21);
for(size_t i=0; i<valary.size(); ++i)
{
valary[i] = i;
}
foo(valary);
}
$ g++ slice_array.cpp
slice_array.cpp: In function ‘void foo(std::valarray<int>&)’:
slice_array.cpp:6:42: error: invalid initialization of non-const reference of type ‘std::slice_array<int>&’ from an rvalue of type ‘std::slice_array<int>’
slice_array<int>& sa = va[slice(0,3,2)];
^
ASKER
As noted in the OP, VS 2010 Express built the above program and it ran as expected. Not sure why that is. Could it be running C++11 instead of C++03? Can I force it to run C++03 as that is what my project uses?
My book says:
I would like VS 2010 Express to behave the same way as g++.
(Be back in 12 hrs.)
My book says:
slice_array<T> operator[](slice); // references to elements
A slice_array can be copied.A book from 1997 does say that that slice_arrays cannot be copied, but it does have code similar to the OP code (without a need for adding a const).
I would like VS 2010 Express to behave the same way as g++.
(Be back in 12 hrs.)
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
My book says:
slice_array<T> operator[](slice); // references to elements
from syntax slice_array<T> is an object and not a reference. internally it could be a reference (pointer) nevertheless.
the msdn reference says:
The class describes an object that stores a reference to an object of class valarray<Type>, along with an object of class slice, which describes the sequence of elements to select from the valarray<Type> object.
The template class is created indirectly by certain valarray operations and cannot be used directly in the program. An internal, auxiliary template class that is used by the slice subscript operator:
slice_array<Type> valarray<Type::operator[] (slice).
You construct a slice_array<Type> object only by writing an expression of the form va[sl], for a slice sl of valarray va. The member functions of class slice_array then behave like the corresponding function signatures defined for valarray<Type>, except that only the sequence of selected elements is affected.
the visual c++ creates a new temporary object slice_array which therefore can be referenced as lvalue.
the standard reference (http://www.cplusplus.com/reference/valarray/valarray/operator%5B%5D/) says (regarding valarray operator[])
valarray<T> operator[] (slice slc) const;
slice_array<T> operator[] (slice slc);
...
The subscript access versions (2) return a sub-array object that selects the elements specified by its argument:
- If the valarray is const-qualified, the function returns a new valarray object with a copy of this selection.
- Otherwise, the function returns a sub-array object, which has reference semantics to the original array, ready to be used as an l-value.
you see the visual c++ implementation is more compliant to the (both C98 and C++11) standard as it is with g++.
'A slice_array can be copied' versus slice_arrays cannot be copiedin the msdn i read somewhere the statement that slice_array objects cannot be copied. since you can prevent from copying by defining a private copy constructor and a private operator= it is rather simple. but actually i didn't see a reson why copies should be forbidden. obviously you could create copies anyhow by using the expression va[sl] twice.
the following code compiles (visual studio 2010):
std::valarray<int> va(3);
std::slice sl(0,2, 2);
std::slice_array<int> sa1 = va[sl];
std::slice_array<int> sa2 = sa1;
what proves that the copy constructor of slice_array was working.I would like VS 2010 Express to behave the same way as g++.as told the behavior of vc compiler is compliant to the standard while g++ seems to support valarray operator[] const only and returns an rvalue. i wonder whether g++ allows to create copies of slice_array. if so, you probably should go this way for both platforms rather than to use local references to va[sl]. where the behavior is different.
Sara
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Also note that if you are using C++ 11 you can simplify your code to just the following:
or
or
http://en.cppreference.com/w/cpp/language/auto
auto const & sa = va[slice(0,3,2)]; // bind to const ref
or
auto && sa = va[slice(0,3,2)]; //; bind to r-value ref
or
auto sa = va[slice(0,3,2)]; //; take a copy of the returned value
http://en.cppreference.com/w/cpp/language/auto
>> as told the behavior of vc compiler is compliant to the standard
Oh, if only it was :(
Oh, if only it was :(
returns an r-value (a temporary object in this case).
actually the standard doesn't support this assertment. a temporary object and a rvalue are two different things. an rvalue only could be used for the right side of an assignment. a temporary object is an lvalue within the current scope.
the docs for slice_array didn't change from C++98 to C++11. and you can find the following at http://www.cplusplus.com/reference/valarray/valarray/operator%5B%5D/
Otherwise, the function returns a sub-array object, which has reference semantics to the original array, ready to be used as an l-value.what obviously is in contradiction to the visual c++ compiler verdict evilrix has posted.
note, the main purpose of a slice_array object is to provide a comfortable filter to a valarray. the only way to get a slice_array is via valarray operator[slice]. we can recognize a lot of bewilderment - unfortunately also here in this thread - regarding the nature of an object returned by value. but there is no doubts even if it is a temporary, an object returned by value is not an rvalue. if we accept this, g++ obviously doesn't return a temporary helper object but a const reference to either slice_array or valarray what is as far as i can see a contradiction to that what the standard says.
Sara
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
The only way to preserve it is to bind it to a const l-value reference, an r-value reference or take a copy.
again, it is a different thing that a temporary would not "preserve" if you don't bind it to a const reference or take a copy to the fact that it could be used as a lvalue. so the slice_array object returned by va[sl] is a temporary but also can be used as lvalue, what means that you could apply any non-const member function or non-const operator directly by statements like va[sl] *= 10; what apparently could not work if va[sl] was an rvalue.
or:
class X
{
int m;
public:
X(int i) : m(i) {}
static X GetX(int k) { return X(k); }
X& operator=(int n) { m = n; return *this; }
friend std::ostream & operator<<(std::ostream & os, const X & x) { os << x.m; return os; }
};
void f()
{
std::cout << (X::GetX(999) = 5) << std::endl;
}
rvalue or lvalue?
Sara
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks for this discussion. I appreciate that. I got home much later than expected and now it is past midnight. I will spend more time on this (and I do have Friday off - maybe even Thursday if I get more time in tomorrow along with some success!).
Sorry to be so brief in what should be a more detailed engagement. :(
@jkr - I ran your 2nd program on both VS 2010 Express and g++ to confirm the results. Thanks. It worked without needing const and even without an extra temp. At work I will eventually be doing timing tests. I don't think using a slice_array object will cause much of an issue as long as the reference semantics hold when referring to the valarray object. I use VS 2010 instead of 2013 because I was concerned that C++11 goodies might creep in, and my project is not C++11. (Neither is it pure C++11, because I accidentally found that I could define on the stack an array (even 2d) whose dimension lengths are passed in as function arguments - worked with g++ as well as Intel compilers.)
@sara - your suggested program does work, but I was trying to get my book's style working, and it looks like jkr cracked the l-value, r-value issue (at least as a work-around without introducing const). I believe that "sa" in the OP code is a reference to a slice_array object and that its usage provides reference semantics to the underlying valarray. That was my hope. The intention was to be able to refer to the original valarray object elements in the slice without having to actually copy the slice over to another valarray object. (This exercise is a prelude to using gslice_array on valarrays that are very large, and I would like to try to avoid copying sub-matrix.)
I believe the answer to your question as to why certain operations are prohibited has to do with compiler optimizations that can be performed if the compiler knows that no aliasing will occur. When you seemed to imply that my book was wrong with regards to reference semantics, I started to look at the C++03 standard (and that's why I use the book to avoid that). But that leads to ...
@rx - Glad you joined in because I am hoping to understand what the standard really is saying now that I started looking at it. My post is a simplified version of the book's code (which is already pretty simple), so I wasn't surprised when VS 2010 Express worked. Book is BS's 4th edition, but 3rd special edition has same sample code. Still trying to figure out whether one compiler has a bug, or whether there needs to be flags set to make them strictly conforming to C++03. My boss (and I) should know whether I am producing pure conforming code.
BTW - in the OP I noted that C++11 is not available on my project, so I hope to continue this discussion in a C++03 vein. At work today, I tried using our actual Intel compiler and got the same rvalue error. So, I am still confused as to which compilers are conforming. (I used to think I understood rvalue/lvalue in my C days a long time ago.)
@all:
fyi - The lead asked me to try to come up with a high performance method of using valarray because Intel compiler has flags to enable SIMD when using it. He apparently wasn't happy with previous attempts to make use of it. (And I didn't see any slice_array or gslice_array in their classes, so I am guessing that may be a source of the performance hit due to copying and temporaries being created - just a WAG at this point.) From my other valarray question, you can see that I learned how to create a sub-matrix using gslice_array. But I think there may be copy operations going on that I hope to avoid.
I find it odd that various online resources seem to say opposite things about slice_array w.r.t. the ability to use it explicitly in a program. Yet, jkr's solution shows working programs that explicitly mention slice_arrays and they work on at least two compilers.
Thanks all. Will read all of this in more detail in a few days (or a little at a time).
Sorry to be so brief in what should be a more detailed engagement. :(
@jkr - I ran your 2nd program on both VS 2010 Express and g++ to confirm the results. Thanks. It worked without needing const and even without an extra temp. At work I will eventually be doing timing tests. I don't think using a slice_array object will cause much of an issue as long as the reference semantics hold when referring to the valarray object. I use VS 2010 instead of 2013 because I was concerned that C++11 goodies might creep in, and my project is not C++11. (Neither is it pure C++11, because I accidentally found that I could define on the stack an array (even 2d) whose dimension lengths are passed in as function arguments - worked with g++ as well as Intel compilers.)
@sara - your suggested program does work, but I was trying to get my book's style working, and it looks like jkr cracked the l-value, r-value issue (at least as a work-around without introducing const). I believe that "sa" in the OP code is a reference to a slice_array object and that its usage provides reference semantics to the underlying valarray. That was my hope. The intention was to be able to refer to the original valarray object elements in the slice without having to actually copy the slice over to another valarray object. (This exercise is a prelude to using gslice_array on valarrays that are very large, and I would like to try to avoid copying sub-matrix.)
I believe the answer to your question as to why certain operations are prohibited has to do with compiler optimizations that can be performed if the compiler knows that no aliasing will occur. When you seemed to imply that my book was wrong with regards to reference semantics, I started to look at the C++03 standard (and that's why I use the book to avoid that). But that leads to ...
@rx - Glad you joined in because I am hoping to understand what the standard really is saying now that I started looking at it. My post is a simplified version of the book's code (which is already pretty simple), so I wasn't surprised when VS 2010 Express worked. Book is BS's 4th edition, but 3rd special edition has same sample code. Still trying to figure out whether one compiler has a bug, or whether there needs to be flags set to make them strictly conforming to C++03. My boss (and I) should know whether I am producing pure conforming code.
BTW - in the OP I noted that C++11 is not available on my project, so I hope to continue this discussion in a C++03 vein. At work today, I tried using our actual Intel compiler and got the same rvalue error. So, I am still confused as to which compilers are conforming. (I used to think I understood rvalue/lvalue in my C days a long time ago.)
@all:
fyi - The lead asked me to try to come up with a high performance method of using valarray because Intel compiler has flags to enable SIMD when using it. He apparently wasn't happy with previous attempts to make use of it. (And I didn't see any slice_array or gslice_array in their classes, so I am guessing that may be a source of the performance hit due to copying and temporaries being created - just a WAG at this point.) From my other valarray question, you can see that I learned how to create a sub-matrix using gslice_array. But I think there may be copy operations going on that I hope to avoid.
I find it odd that various online resources seem to say opposite things about slice_array w.r.t. the ability to use it explicitly in a program. Yet, jkr's solution shows working programs that explicitly mention slice_arrays and they work on at least two compilers.
Thanks all. Will read all of this in more detail in a few days (or a little at a time).
evilrix, i hope you pardon me if i don't want to dive into the swamp of rvalue, lvalue, prvalue, xvalue, since i am not a compiler expert and much less experienced in studying the secrets of describing a standard than you. i reread all the comments and quotes you made and think i have found a sufficient explanation (sufficient for me) of the difference between the two compilers regarding the temporary slice_array: the difference is the lifetime of the temporary where the standard only guarantees that it is preserved until end-of-scope if it either was copied or bound to a const reference while visual c++ compiler also holds the temporary alive if you bind it to a non-const reference.
phoffric, jkr's code made a copy of the temporary slice_array and then an alias to that local copy. since we already knew that copying of slice_array objects was allowed and because taking a copy of a temporary is a valid means to extend the lifetime of the temporary until end-of-scope, the workaround is safe.
but also may confuse again if we think about the following assertments made:
Sara
it looks like jkr cracked the l-value, r-value issue (at least as a work-around without introducing const).
phoffric, jkr's code made a copy of the temporary slice_array and then an alias to that local copy. since we already knew that copying of slice_array objects was allowed and because taking a copy of a temporary is a valid means to extend the lifetime of the temporary until end-of-scope, the workaround is safe.
I believe that "sa" in the OP code is a reference to a slice_array object and that its usage provides reference semantics to the underlying valarray. That was my hope.a slice_array doesn't store own values but has references to valarray elements. in any case the slice_array allows manipulation of the original values within its lifetime. because of that the following code also should work (for both compilers):
void foo(valarray<int>& va)
{
va[slice(0,3,2)] = 98;
}
but also may confuse again if we think about the following assertments made:
All "rvalue" means is that it cannot appear on the left hand side of an assignment.
with the deepest respect, you are wrong!
(I used to think I understood rvalue/lvalue in my C days a long time ago.)perhaps we come to the conclusion that all these statements stretch the truth :-)
Sara
ASKER
Here is the code from The C++ Programming Language, 4th Edition by Bjarne Stroustrup (and I think the function is the same as in the 3rd Special Edition).
A user cannot directly create a slice_array. Instead, the user subscripts a valarray to create a slice_array for a given slice. Once the slice_array is initialized, all references to it indirectly go to the valarray for which it is created. For example, we can create something that represents every second element of an array like this:
void f(valarray<double>& d)
{
slice_array<double>& v_even = d[slice(0,d.size()/2+d.size()%2,2)];
slice_array<double>& v_odd = d[slice(1,d.size()/2,2)];
v_even *= v_odd; // multiply element pairs and store results in even elements
v_odd = 0; // assign 0 to every odd element of d
}
This code builds/runs well on VS 2010 Express. So, I naively thought that VS was correct and that something was wrong with g++, and was hoping that maybe a g++ flag would set things straight so that I can write one piece of code that works the same on both platforms.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I see that there were some errata to The Programming Language on the BS code; yet attempts to get them into later releases failed. Other online searches seems to suggest that VS 2010 allows non-portable C++ code (on the topic of referencing rvalues) to be built. There is a semantic debate as to whether VS is a non-compliant compiler which builds all correct code, but allows extensions (so as to be non-portable).
Right now, I believe that g++ is giving the correct error, and VS (perhaps due to default config settings) is not.
I will check tomorrow if the /Za switch is set to "Disable Language Extensions" to see if I can force VS to give an error.
https://msdn.microsoft.com/en-us/library/0k0w269d.aspx
Right now, I believe that g++ is giving the correct error, and VS (perhaps due to default config settings) is not.
I will check tomorrow if the /Za switch is set to "Disable Language Extensions" to see if I can force VS to give an error.
https://msdn.microsoft.com/en-us/library/0k0w269d.aspx
Gcc is giving the correct error. You cannot bind an rvalue to an lvalue reference. This is why rvalue references were introduced in C++11. VS2010 is wholly non-standard compliant. Later versions are better, but still take liberties.
If you can't use C++11 (better rethink this as C++14 will be the standard soon) your only choice is to take a copy of the returned value. Since the object is designed to have reference semantics to the original array, this is perfectly correct, if slightly inefficient.
If you can't use C++11 (better rethink this as C++14 will be the standard soon) your only choice is to take a copy of the returned value. Since the object is designed to have reference semantics to the original array, this is perfectly correct, if slightly inefficient.
>> I used to think I understood rvalue/lvalue in my C days a long time ago
Actually, there's nothing super magical about either.
lvalues are entities that may exist on the left (and right) hand side of an assignment.
rvalues may only appear on the right hand side of an assignment.
That's it. There is nothing else specifically prescribed to either. For example, an lvalue, by definition, can't be const but an rvalue doesn't have to be. The C++11 standard expands on these definitions and introduces xvalues, gvalues and pure rvalues, but these are just refinements of these two basic types.
My advise is to not worry too much about what lvalue or rvalue means, just remember that a temporary (and when a function returns by value it always creates a temporary*) can never be bound to a non-const C++03 style reference.
* The C++03 standard allows for Return Value Optimisation; however, the semantics of the result being an lvalue do not change. Further, C++11 introduced rvalue references, and by default temporary values are returned using move rather than copy semantics. Again, the result is still an rvalue!
>> evilrix, i hope you pardon me if i don't want to dive into the swamp of rvalue, lvalue, prvalue, xvalue
Truthfully, I don't blame you. The standard document can be hard to read and even harder to follow. It was written by very smart people to be a guide for compiler writers. It is the final point of call when arbitrating a confusion with the language but that doesn't mean it is the best place to go (at least, not unless you want you brain frazzled). I often find myself reading the same paragraph over and over and over and, each time, thinking it is telling me something different. Fortunately, on this particular subject I find it to be pretty clear (at least, I think I do - heh).
Actually, there's nothing super magical about either.
lvalues are entities that may exist on the left (and right) hand side of an assignment.
rvalues may only appear on the right hand side of an assignment.
That's it. There is nothing else specifically prescribed to either. For example, an lvalue, by definition, can't be const but an rvalue doesn't have to be. The C++11 standard expands on these definitions and introduces xvalues, gvalues and pure rvalues, but these are just refinements of these two basic types.
My advise is to not worry too much about what lvalue or rvalue means, just remember that a temporary (and when a function returns by value it always creates a temporary*) can never be bound to a non-const C++03 style reference.
* The C++03 standard allows for Return Value Optimisation; however, the semantics of the result being an lvalue do not change. Further, C++11 introduced rvalue references, and by default temporary values are returned using move rather than copy semantics. Again, the result is still an rvalue!
>> evilrix, i hope you pardon me if i don't want to dive into the swamp of rvalue, lvalue, prvalue, xvalue
Truthfully, I don't blame you. The standard document can be hard to read and even harder to follow. It was written by very smart people to be a guide for compiler writers. It is the final point of call when arbitrating a confusion with the language but that doesn't mean it is the best place to go (at least, not unless you want you brain frazzled). I often find myself reading the same paragraph over and over and over and, each time, thinking it is telling me something different. Fortunately, on this particular subject I find it to be pretty clear (at least, I think I do - heh).
Gcc is giving the correct error.phoffric, if the c++ code you posted is from a Stroustrup book, then Stroustrup is not using gcc, obviously.
You cannot bind an rvalue to an lvalue reference.if the temporary object returned from valarray operator[] is an rvalue, why statements like va[sl] *= 10; would compile? why does the reference for valarray at cplusplus.com state "valarray::operator[slice]
your only choice is to take a copy of the returned value.since you can modifiy the returned object directly, a copy solves the issue and improves readability but is not the "only" way.
i tried to understand all the links and statements evilrix has posted regarding the rvalue status of a temporary. i think he is right that the current standard doesn't allow to make an alias (a reference variable) of a temporary returned by a function. the reason for this may be due to the factor that container elements may be "moved" rather than be copied such that the lifetime of the temporary must end with the current statement (and the initialization of an alias already is the next statement). i wonder though why a const reference still is valid until end-of-scope though of course manipulating the underlying valarray also could make those variables corrupt or point to wrong elements.
Sara
It's returns an object with reference semantics. Think of it as a smart pointer object but rather than having pointer semantic it has reference semantics. In other words, it returns an object by value but that object references the original array.
A temporary bound to a reference has the same lifetime of the reference to which it is bound. Why? Because that is that the standard prescribes.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thank you for your detailed responses.
did you try to use a const reference variable. a slice neither can be constructed nor be copied. because of that all public member functions actually should be const anyway.
Sara