Wunused-but-set-variable warning with C++11 auto - c++

I am getting a -Wunused-but-set-variable warning with GCC v4.6 with the code below:
for ( auto i : f.vertexIndices ) {
Sy_MatrixFuzzyHashable< Vector3f > wrapper( cp );
if ( !vMapper.contains( wrapper ) ) {
mesh.vertexNormals() << cp;
i.normal = mesh.vertexNormals().size() - 1;
} else {
i.normal = vMapper.value( wrapper );
}
}
The warning specifically is:
warning: variable 'i' set but not used [-Wunused-but-set-variable]
The warning would make sense if i was a copy of an element, but since vertexIndices is a QList object (an STL-compliant Qt container class) the range-based for loop should call the begin() and end() iterator getters, which will always return a non-const iterator (as long as the container is non-const - which it is).
I can't currently test if it is working as I think it should because I'm changing my code base to take advantage of the new C++11 features, so nothing compiles yet. But I was hoping someone could tell me if this warning is is nonsense, or if I have misunderstood auto and range-based for loops...

I think the issue is that your for loop, as written like this:
for ( auto i : f.vertexIndices )
is getting back a copy of the stored vertex, not a reference to it. The compiler warning here says that you're then setting the value of i but not reading it because you're modifying the temporary copy rather than the stored vertex.
If you change it to
for ( auto& i : f.vertexIndices )
then this problem should go away, since you're actually modifying the vertices stored internally.
Hope this helps!

You misunderstood auto. This loop:
for ( auto i : f.vertexIndices )
should really be :
for ( auto & i : f.vertexIndices )

http://en.wikipedia.org/wiki/Foreach_loop#C.2B.2B
illustrates an example but yes, it needs to be a reference object for the foreach
#include <iostream>
int main()
{
int myint[] = {1,2,3,4,5};
for (int& i: myint)
{
std::cout << i << std::endl;
}
}
or
#include <QList>
#include <QDebug>
int main() {
QList<int> list;
list << 1 << 2 << 3 << 4 << 5;
foreach (int i, list) {
qDebug() << i;
}
}
Courtesy of Wikipedia

Related

c++ will compiler optimize argument by value to argument by rvalue reference?

I think to recall that someone told me that these two methods
foo(std::vector<int>&& v) {
member = std::move(v);
}
bar(std::vector<int> v) {
member = std::move(v);
}
both will not invoke a copy if there is a move at the call site
foo(std::move(v1));
bar(std::move(v2));
since the compiler will optimize the call and treat the bar case as if it would take the argument by rvalue reference and therefore one should favor the bar syntax since it's less convoluted and can also be called with an lvalue (in which case of course a copy will be made).
Is this true? can one rely on the barcase not creating a copy so long as one calls it with an rvalue?
can one rely on the bar case not creating a copy so long as one calls it with an rvalue?
No, not necessarily.
An example in which a copy will take place:
const std::vector<int> vec;
bar( std::move(vec) );
Here std::move will cast vec (an lvalue) to an xvalue (i.e. rvalue). But it won't be moved since vec is constant and can not be modified. Thus the move constructor of std::vector won't be called.
Now I tried your code with a bit of modification in godbolt and I got the results that you expected.
This code:
#include <iostream>
#include <vector>
#include <utility>
void foo( std::vector<int>&& v )
{
auto member = std::move(v);
}
void bar( std::vector<int> v )
{
auto member = std::move(v);
}
int main( )
{
std::vector<int> v1(3, 1000);
std::vector<int> v2(3, 2000);
//foo( std::move(v1) ); // uncomment this
//bar( std::move(v2) ); // uncomment this
bar( v2 ); // and comment this out
for ( const auto& num : v1 )
{
std::cout << num << ' ';
}
std::cout << '\n';
for ( const auto& num : v2 )
{
std::cout << num << ' ';
}
std::cout << '\n';
}
First, you will see the output as:
1000 1000 1000
2000 2000 2000
But then do the things I mentioned above and you will see that the output will disappear. This is because after moving the two vectors, they will become empty due to losing ownership of their buffer. So the for-loops will print nothing. This really proves that a move is happening in bar( std::move(v2) );. And bar( v2 ); is a deep copy.

Vector of non-const objects seems to be treated as constant in range-based for loop

I have a std::vector of objects being filled by de-referencing std::unique_ptr's in the push_back calls. However, when I run through a mutable range-based for-loop, my modification to these objects stays local to the loop. In other words, it seems as those objects are being treated as constant, despite that lack of a const keyword in the loop. Here is minimal code to demonstrate what I'm seeing:
#include <vector>
#include <memory>
#include <iostream>
class Item
{
public:
typedef std::unique_ptr<Item> unique_ptr;
inline static Item::unique_ptr createItem()
{
return std::unique_ptr<Item>(new Item());
}
inline const int getValue() const { return _value; }
inline void setValue(const int val) { _value = val; }
private:
int _value;
};
int main()
{
std::vector<Item> _my_vec;
for (int i = 0; i < 5; i++)
{
Item::unique_ptr item = Item::createItem();
_my_vec.push_back(*item);
}
for (auto item : _my_vec)
{
// modify item (default value was 0)
item.setValue(10);
// Correctly prints 10
std::cout << item.getValue() << std::endl;
}
for (auto item : _my_vec)
{
// Incorrectly prints 0's (default value)
std::cout << item.getValue() << std::endl;
}
}
I suspect this has something to do with the move semantics of std::unique_ptr? But that wouldn't quite make sense because even if push_back is calling the copy constructor or something and copying the added item rather than pointing to it, the iterator is still passing over the same copies, no?
Interestingly enough, in my actual code, the class represented here by Item has a member variable that is a vector of shared pointers to objects of another class, and modifications to the objects being pointed to by those shared pointers persist between loops. This is why I suspect there's something funky with the unique_ptr.
Can anyone explain this behavior and explain how I may fix this issue while still using pointers?
When you write a range-based for loop like that:
std::vector<int> v = ...;
for(auto elt : v) {
...
}
the elements of v are copied into elt.
In your example, in each iteration, you modify the local copy of the Item and not the Item in the vector.
To fix your issue, use a reference:
for (auto& item : _my_vec)
{
item.setValue(10);
std::cout << item.getValue() << std::endl;
}
Vector of non-const objects seems to be treated as constant
If it was treated as constant, then the compiler would scream at you, because writing to a constant is treated as ill-formed and the compiler would be required to scream at you. The shown code compiles just fine, with no warnings.
I suspect that you may be referring to the fact that you don't modify the elements within the vector. That is because you modify auto item. That item is not an element of the vector, it is a copy of the item in the vector. You could refer to the item within that vector by using a reference: auto& item. Then modifications to item would be modifications to the referred element of the vector.

Modify a vector by changing its pointer doesn't work in c++?

Below is the snippet, I want to point the first variable to the second variable without copying the vector:
#include <iostream>
#include <vector>
std::vector<int> second (4,100);
void modify(std::vector<int>* i) {
i = &second;
}
int main ()
{
std::vector<int> first; // empty vector of ints
modify(&first);
for (std::vector<int>::iterator it = first.begin(); it != first.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
The output is empty, while I expected the output to be 100 100 100 100.
Does anyone have ideas about why can't I modify the vector like this?
You're passing the pointer by value. That means anything you change the pointer to point to in the function will not be seen outside the function. What you need to do is pass the pointer by reference if you want to see the changes in the call site. This won't work in this case though since
modify(&first);
is a rvalue pointer and cannot be bound to a non const lvalue reference.
All of this though is not needed. We can just change the function to take a reference like
void modify(std::vector<int>& i) {
i = second;
}
and then modify(&first); becomes modify(first); and now the changes will be reflected in main().
Looks like you wanted this instead:
void modify(std::vector<int>* i) {
*i = second;
}
it is "old" way to modify value through parameter and it may have an issue:
void modify(std::vector<int>* i) {
if( !i ) {
// what should I do?
throw std::runtime_exception( "cannot modify vector through nullptr" );
}
*i = second;
}
this additional check can be avoided using reference instead which also would make your intention clearer to the reader of the code, unless you really want to pass nullptr sometimes for some reason (tell function not to change value, but do something else for example).

std::cout of string not working

I have a class State that has a string data type called moveType. In the implementation of my code, I am calling a setter void setMoveType(string _moveType); and it's implemented with just moveType = _moveType;
When I call my getter string getMoveType() const; on an instance of State and output it to cout, nothing is displayed.
I am couting upon entering the getMoveType() function. The parameter indeed has the correct value, but it appears that it's not getting set at all.
Does anyone have any idea? I feel this is something simple/trivial in c++ that I'm just completely forgetting.
string State::getMoveType() const {
return moveType;
}
void State::setMoveType(string move_type) {
cout << "In setMoveType and param = " << move_type << endl;
moveType = move_type;
}
std::cout << vec_possibleSuccessors[i].getMoveType() << endl; // within loop;
vector<State> vec_possibleSuccessors;
if (_minState.canMoveUp()) {
up = _minState.moveUp();
up.setMoveType("UP");
up.setF(f(up));
vec_possibleSuccessors.push_back(up);
}
In the above code, _minState and up are instances of State. Also, I have made sure that my copy constructor and assignment operator have been modified to include moveType assignments.
There isn't really enough code to know for sure, but I have a guess: Either you actually assigned to a shadowed variable in the "set" function and never set the class attribute at all, or your State object has actually been destroyed and the string becomes empty (since being empty is one possible option when using destroyed memory).
Well not an answer but a short example that works the way you seem to intend this to work:
#include <string>
class State
{
private:
std::string m_moveType;
public:
State() : m_moveType( "unknown" ) {}
std::string getMoveType() const { return m_moveType; }
void setMoveType( const std::string& moveType ) { m_moveType = moveType; }
};
In your main function or were else you need a vector of States you could write this:
#include <iostream>
#include <vector>
#include "State.h"
int main()
{
std::vector< State > states;
for( int i=0; i<10; ++i )
{
State newState;
newState.setMoveType( "state" );
states.push_back( newState );
}
// do whatever you need to do....
std::vector< State >::iterator it;
std::vector< State >::iterator end = states.end();
for( it=states.begin(); it != end; ++it )
std::cout << (*it).getMoveType() << std::endl;
return 0;
}
A few remarks:
passing parameters by value like setMoveType( string s ) is not
adviseable, pass const references instead. Passing by value incurrs a
full copy of the passed object
be careful with includes and namespaces, in doubt take the extra time
to type std::... if you intend to use a feature defined in namespace
std, and never type using namespace std in a header file.
initialize private members to a sensible default and do it in the class
initializer list
I'm not sure on this either, but you appear to be storing this State in a vector. Could you post the code to how you set elements in the vector? Its important to note that you can't update an element in a vector once its inserted (unless you store a pointer to the element). Also depending upon how you call set, there may be problems.

Question on function references and threads

I was randomly testing std::thread in my virtual linux machine (GCC 4.4.5-Debian) with this test program:
#include <algorithm>
#include <thread>
#include <iostream>
#include <vector>
#include <functional>
using namespace std;
static int i=0;
void f( vector<int> &test)
{
++i;
cout << "Push back called" << endl;
test.push_back(i);
}
int main()
{
vector<thread> t;
vector<int> test;
for( int i=0; i<1000; ++i )
{
t.push_back( thread( bind(f, test) ) );
}
for( auto it = t.begin(); it != t.end(); ++it )
{
(*it).join();
}
cout << test.size() << endl;
for( auto it = test.begin(); it != test.end(); ++it )
{
cout << *it << endl;
}
return 0;
}
Why does vector test remain empty? Am I doing something stupid with references (probably) or is it something with bind or some threading problem?
Thanks!
UPDATE: with the combined help of Kos and villintehaspan I "fixed" the "problem":
#include <algorithm>
#include <thread>
#include <iostream>
#include <vector>
#include <functional>
using namespace std;
static int i=0;
void f( vector<int> &test)
{
++i;
test.push_back(i);
}
int main()
{
vector<thread> t;
vector<int> test;
for( int i=0; i<1000; ++i )
{
t.push_back( thread(f, std::ref(test)) );
}
for( auto it = t.begin(); it != t.end(); ++it )
{
(*it).join();
}
cout << test.size() << endl;
for( auto it = test.begin(); it != test.end(); ++it )
{
cout << *it << endl;
}
return 0;
}
Which prints all values in order and seems to work OK. Now only one question remains: is this just lucky (aka undefined behavior (TM) ) or is the static variable causing a silent mutex-like step in the code?
PS: I understand the "killing multithreadedness" problem here, and that's not my point. I'm just trying to test the robustness of the basic std::thread functionality...
Looks to me like a threading problem.
While I'm not 100% sure, it should be noted that all 1000 threads:
do ++i on the same int value (it's not an atomic operation- you may encounter problems here, you can use __sync_fetch_and_add(&i,1) instead (note that it's a gcc extension not standard C++);
do push_back simultaneously on a std::vector, which is not a thread-safe container AFAIK... Same for cout I think. I believe you'd need to use a locking mechanism around that (std::mutex perhaps? I've only used pthreads so far but I believe it's what you need).
Note that this kind of kills any benefit of using threads here, but that's a consequence of the fact that you shouldn't use multiple threads at once on a non-thread-safe object.
----EDIT----
I had a google on this threading API (not present on my tdm gcc 4.5 on Windows, unfortunately).
Aparrently instead of:
thread( bind(f, test) )
you can just say
thread( f, test )
and pass an arbitrary number of arguments in this way.
Source: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=422
This should also solve your problem with making a copy of the vector which I haven't noticed before
(+1 for #villintehaspam here).
Actually, one more thing is needed to make sure the copy isn't created here:
thread( f, std::ref(test) )
will make sure that the vector isn't copied.
Wow, I got confused too. :)
The bind will actually make a copy of the vector, so that each thread push_back's on their own copy (yes, that & won't help here). You need to provide the threads with a pointer or similar so that they use the same vector. You should also make sure to use access protection like suggested by Kos.
Edit: After your fix to use std::ref instead of making a copy of the vector, the multithreaded access problem still remains. My guess is that the only reason you don't get any problems right now is because the example is so trivial (or maybe you've only tried in debug mode) - there is no automatic guarantee that the ++ is atomic just because the int is static.