I have just compiled GCC 4.6.0, and I wanted to try the new features out, starting with the range-based for loop.
The first loop I wanted to change was iterating on a std::vector of pointers. I changed the code to use the new syntax, but it didn't compile.
I have tried to substitute another for loop, which was on a std::vector of structs, and it compiled and ran perfectly.
Here is a short test code to show you my problem:
#include <vector>
#include <iostream>
int main()
{
std::vector< int > values;
values.push_back(2);
values.push_back(5);
values.push_back(8);
values.push_back(13);
values.push_back(17);
for (int &n : values)
{
std::cout << n << "\n";
}
std::vector< int* > pointers;
pointers.push_back(new int(2));
pointers.push_back(new int(5));
pointers.push_back(new int(8));
pointers.push_back(new int(13));
pointers.push_back(new int(17));
for ((int*) &p : values)
{
std::cout << (*p) << "\n";
}
for( unsigned int i = 0; i < pointers.size(); ++i)
{
delete pointers[i];
}
return 0;
}
When I try to compile it (yes, I give -std=c++0x as a parameter to g++), it dies with this error:
main.cpp|27|error: found ‘:’ in nested-name-specifier, expected ‘::’
If I comment the lines 27-30 out, it's OK.
What am I doing wrong? Isn't the pointer-reference declaring syntax right?
Or is there a limitation of contained types where range-based for loops can be used?
for ((int*) &p : values)
This is wrong. (int*) is an expression alone, so you need to do int*& (with no parenthesis, that makes an expression - aka "not a type name") at least to make it correct. I prefer to use auto or auto&, personally.
You can do :
for (auto p : values) // here p is a pointer, a copy of each pointer
or
for (auto& p : values ) // here p is a non-const reference to a pointer
or
for ( int* p : values ) // here p is a copy of each pointer
or in generic code:
for ( auto&& p: values ) // p is either a const reference to what is in values, or a non-const reference, depends on the context
I think you meant to iterate over 'pointers' instead of 'values' there...
Related
I am learning c++ for the first time(I am transitioning from python)
I see some weird behavior when I try to work with and compile ranged loops using multidimensional arrays. Consider the following case:
#include <iostream>
#include <typeinfo>
int array[2][3]
for (dataType row : array) { std::cout << typeid(row).name(); }
If dataType is const int* row, row becomes a pointer (whose elements) cannot be modified. This is expected.
for (const int* row : array) { std::cout << typeid(row).name(); }
output : int const * __ptr64
If dataType is const auto row, row becomes a pointer that CAN be modified. Regardless of whether or not you try to modify the row inside the code, the compiler ignores your request to make row a constant variable.
for (const auto row : array) { std::cout << typeid(row).name(); }
output : int * __ptr64
In the above case, I can modify the contents of row without any errors.
If you add the asterisk after auto, you will now get a constant variable. You need to both, type const, and put the asterisk to make it constant.
for (const auto* row : array) { std::cout << typeid(row).name(); }
output : int const * __ptr64
Now, if we put the & operator instead of an asterisk, row will become an array of size 3. Here, & isn't modifying the address or anything, I cannot find a way to force the compiler to copy the inner array and put it inside row at a new address. This just makes it easier to work with nested ranged loops.
for (auto& row : array) { std::cout << typeid(row).name(); }
output : int [3]
But now, I cannot manually tell the compiler to make an array. Typing in something like int row[3] won't even get compiled. The only way to get an array is to use auto&
for (int row[3] : array) { std::cout << typeid(row).name(); }
CompilerError E0144: a value of type "int*" cannot be used to initialize an entity of type "int[3]"
for (int& row[3] : array) { cout << typeid(n).name(); }
CompilerError E0144: a value of type "int*" cannot be used to initialize an entity of type "int[3]"
CompilerError E0251: array of reference is not allowed
I like to use nested ranged loops in my code, its a habit I developed while using python. It makes the code much easier to write, read and it's much less error prone. For the sake of readability and debugging, I want a way to force my compiler to initialize row as an array instead of using auto& and letting the compiler decide what dataType it wants for the array.
Also, I want a way to get a deep copy of row at another address so I can modify the contents inside my loop without making changes to the original array. For one dimensional loops, omitting the & operator will make a copy of the data at a different address, but with multidimensional arrays, its always the same address.
It would also be nice to know what is going on when you initialize with const auto as opposed to const auto*. What does adding the asterisk do that is so important for the compiler?
C-arrays are not copyable and have strange/ugly syntax for reference type.
I suggest to use std::array which is a good replacement.
std::array<std::array<int, 3>, 2> array;
for (/*const*/ std::array<int, 3> /*&*/ row : array) {
for (int /*&*/ e : row) {
// ...
}
}
for (/*const*/ auto /*&*/ row : array) {
for (auto /*&*/ e : row) {
// ...
}
}
C-array only allow pass by reference (else decays to pointer)
int array[2][3];
for (/*const*/ int (&row)[3] : array) {
for (int /*&*/ e : row) {
// ...
}
}
for (/*const*/ auto & row : array) {
for (auto /*&*/ e : row) {
// ...
}
}
Credit to M.M:
for (const auto row : array) { std::cout << typeid(row).name(); }
auto here becomes a pointer, then const is applied to it. It is a pointer, the address stored in the pointer cannot change but the value it points to can be changed.
It is the same as writing:
int* const row
conversely const auto* simply becomes const int* as expected.
The compiler reads left to right so here const int* is equivalent to (const int)* which creates a pointer to the datatype const int whereas int* const creates a pointer then applies const to that pointer.
Credit to Igor Tandetnik:
To reference a sub array you need to write the following:
for (int (&row)[3] : array) {}
For a multidimensional arrays, the general syntax would be :
dataType array[a][b][c][d](...) ;
for (dataType (&row)[b][c][d](...) : array) {}
To copy an array, you can use a pointer and do it manually with a for loop. Depending on what you're doing, you should choose whether or not you want to allocate it on the heap. Alternatively, there are c++ libraries that give you copy() functions.
If I define a pointer to an object that defines the [] operator, is there a direct way to access this operator from a pointer?
For example, in the following code I can directly access Vec's member functions (such as empty()) by using the pointer's -> operator, but if I want to access the [] operator I need to first get a reference to the object and then call the operator.
#include <vector>
int main(int argc, char *argv[])
{
std::vector<int> Vec(1,1);
std::vector<int>* VecPtr = &Vec;
if(!VecPtr->empty()) // this is fine
return (*VecPtr)[0]; // is there some sort of ->[] operator I could use?
return 0;
}
I might very well be wrong, but it looks like doing (*VecPtr).empty() is less efficient than doing VecPtr->empty(). Which is why I was looking for an alternative to (*VecPtr)[].
You could do any of the following:
#include <vector>
int main () {
std::vector<int> v(1,1);
std::vector<int>* p = &v;
p->operator[](0);
(*p)[0];
p[0][0];
}
By the way, in the particular case of std::vector, you might also choose: p->at(0), even though it has a slightly different meaning.
return VecPtr->operator[](0);
...will do the trick. But really, the (*VecPtr)[0] form looks nicer, doesn't it?
(*VecPtr)[0] is perfectly OK, but you can use the at function if you want:
VecPtr->at(0);
Keep in mind that this (unlike operator[]) will throw an std::out_of_range exception if the index is not in range.
There's another way, you can use a reference to the object:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {7};
vector<int> *p = &v;
// Reference to the vector
vector<int> &r = *p;
cout << (*p)[0] << '\n'; // Prints 7
cout << r[0] << '\n'; // Prints 7
return 0;
}
This way, r is the same as v and you can substitute all occurrences of (*p) by r.
Caveat: This will only work if you won't modify the pointer (i.e. change which object it points to).
Consider the following:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {7};
vector<int> *p = &v;
// Reference to the vector
vector<int> &r = *p;
cout << (*p)[0] << '\n'; // Prints 7
cout << r[0] << '\n'; // Prints 7
// Caveat: When you change p, r is still the old *p (i.e. v)
vector<int> u = {3};
p = &u; // Doesn't change who r references
//r = u; // Wrong, see below why
cout << (*p)[0] << '\n'; // Prints 3
cout << r[0] << '\n'; // Prints 7
return 0;
}
r = u; is wrong because you can't change references:
This will modify the vector referenced by r (v)
instead of referencing another vector (u).
So, again, this only works if the pointer won't change while still using the reference.
The examples need C++11 only because of vector<int> ... = {...};
You can use it as VecPrt->operator [] ( 0 ), but I'm not sure you'll find it less obscure.
It is worth noting that in C++11 std::vector has a member function 'data' that returns a pointer to the underlying array (both const and non-const versions), allowing you to write the following:
VecPtr->data()[0];
This might be an alternative to
VecPtr->at(0);
which incurs a small runtime overhead, but more importantly it's use implies you aren't checking the index for validity before calling it, which is not true in your particular example.
See std::vector::data for more details.
People are advising you to use ->at(0) because of range checking. But here is my advise (with other point of view):
NEVER use ->at(0)! It is really slower. Would you sacrifice performance just because you are lazy enough to not check range by yourself? If so, you should not be programming in C++.
I think (*VecPtr)[0] is ok.
As inspired by Demo of shared ptr array
I got the first two lines to work:
std::shared_ptr<string> sp( new string[3], []( string *p ) { delete[] p; } );
*sp = "john";
auto p = &(* sp);
++p = new string("Paul");
++p = new string("Mary");
for(auto q = &(*sp); q <= p; q++) cout << *q << endl;
(1) Can someone show me how to access subsequent elements of my array and print them out with a for loop?
My for loop does not print anything with MSVC V19 and and g++ v4.9 prints "john" but not "Paul" and "Mary" and then gives me a segmentation fault.
Now after some more google/bing searching I found some discussions suggesting I should use unique_ptr if I are not sharing it.
So I got to experimenting some more and this works:
const int len=3;
std::unique_ptr<string[]> up( new string[len] ); // this will correctly call delete[]
up[0] = "john";
up[1] = "paul";
up[2] = "mary";
for(int ii = 0; ii < len; ++ii) cout << up[ii] << endl;
(2) Is there a way to print the array up without hard coding the length in a constant? I was hoping that there was a way to make the new C++ for loop syntax work but it appears only work on std::array and std::vector.
(3) Is there is an easier way to initialize this array? Perhaps with an initializer list?
To access subsequent elements use the shared_ptr::get member function
std::shared_ptr<string> sp( new string[3], std::default_delete<string[]>() );
sp.get()[0] = "John";
sp.get()[1] = "Paul";
sp.get()[2] = "Mary";
for(auto q = sp.get(); q < sp.get() + 3; q++) cout << *q << endl;
The problem with dereferencing the shared_ptr is that it'll return a string&, but you want to get access to the underlying pointer in order to be able to index to next element.
You can also initialize the shared_ptr array upon construction using list initialization
std::shared_ptr<string> sp( new string[3]{"John", "Paul", "Mary"},
std::default_delete<string[]>() );
As for unique_ptr, as you've noted, there exists a partial specialization that'll delete array types correctly. However, it does not store the length of the array, you'll need to store it separately and pass it around along with the unique_ptr. For one-line initialization you can use the same syntax as above.
std::unique_ptr<string[]> up( new string[len]{"John", "Paul", "Mary"} );
However, neither the shared_ptr nor the unique_ptr can be used with ranged-based for loops. The specification of a range for requires the operand to either be an array, or it must have begin() and end() member functions, or the begin and end iterators for the range must be obtainable by ADL using the expressions begin(__range) and end(__range) respectively. None of these conditions are satisfied by either the shared_ptr or the unique_ptr containing an array.
Unless you have a good reason not to, you should just use std::vector<std::string>, that'll save you the trouble of tracking array length separately. std::array<std::string, N>> is also another option if you know the length of the array at compile time.
With C++17, operator[] is defined for shared_ptr<T[]> (link). Before that it was there for unique_ptr, but not for shared_ptr.
So, the following code will work.
std::shared_ptr<string[]> sp(new string[3]);
sp[0] = "John";
sp[1] = "Paul";
sp[2] = "Mary";
for(int i =0; i< 3; i++)
{
cout<<sp[i]<<"\n";
}
Note that it is define for shared_ptr<T[]>, and not for shared_ptr<T>, i.e. when you have a dynamically allocated array. Also I have removed your custom deleter, as your's is similar to the default one which the compiler will use, you are however free to add it.
For your second query - being able to use new C++ for loop (range based for loop), you cannot use this smart pointer directly, since range based for loop works only on containers which have begin(), end(), operator++, operator*() , and, operator!= defined (link).
The simplest way is to use std::vector with pre-allocated size. eg. vector<T> sp(3), or vector<T> sp; sp.reserve(3). This will work as good as your smart pointers' approach. To get underlying memory you can use vector<T>::data() eg. sp.data(). This will give you a dynamic C array of 3 elements (n elements in general).
How to index into C++ shared_ptr/unique_ptr array?
You've already shown the code for unique_ptr.
This works for shared_ptr.
std::shared_ptr<string> sp( new string[3], []( string *p ) { delete[] p; } );
sp.get()[0] = "string 1";
sp.get()[1] = "string 2";
sp.get()[2] = "string 3";
I'm trying to create a class which maintains a fixed size vector of unique pointers to managed objects, like so:
std::vector<std::unique_ptr<Myclass>> myVector;
The vector gets initialized like so:
myVector.resize(MAX_OBJECTS,nullptr);
Now, what I need to to, is to be able to, on request, remove one of the stored unique pointers without affecting the size of the vector.
I also need to safely add elements to the vector too, without using push_back or emplace_back.
Thanks in advance.
Edit: I want the vector to be of constant size because I want to be able to add and remove elements in constant time.
If you want a vector of fixed size, use std::array.
To remove a unique_ptr in an index, you can use std::unique_ptr::reset():
myVector[i].reset()
To add an element to a specific index (overwriting what was there before) you can use std::unique_ptr::reset() with the new pointer as parameter:
myVector[i].reset(new Myptr(myparameter));
Reading a reference may also help:
http://en.cppreference.com/w/cpp/memory/unique_ptr
http://en.cppreference.com/w/cpp/container/array
http://en.cppreference.com/w/cpp/container/vector
Looks like you want to use a std::array<> rather than forcing std::vector<> to behave like one.
As already pointed out you should use std::array if the size is fixed.
E.g like this:
std::array<std::unique_ptr<YourType>, MAX_OBJECTS> myVector;
You can then remove or add a new pointer like this.
for(auto& v : myVector)
if(v && predicate)
v.reset();// or v.reset(ptr) to set a new one
You can use STL algorithm std::remove, like this:
// all items that should be removed will be the range between removeAt and end(myVector)
auto removeAt = std::remove_if(begin(myVector), end(myVector),
ShouldRemovePredicate);
// reset all items that should be removed to be nullptr
for(auto it = removeAt; it != end(myVector); ++it)
it->reset();
In addition, if the size is known at compile-time I would suggest using std::array<unique_ptr<MyObject>, SIZE> instead of a vector. However, if SIZE is not known at compile-time your code is ok.
You could use std::array instead of a std::vector since you know the number of the elements beforehand and you could add and remove elements like the following example:
#include <iostream>
#include <memory>
#include <array>
class foo {
std::size_t id;
public:
foo() : id(0) {}
foo(std::size_t const _id) : id(_id) {}
std::size_t getid() const { return id; }
};
auto main() ->int {
// construct an array of 3 positions with `nullptr`s
std::array<std::unique_ptr<foo>, 3> arr;
// fill positions
std::unique_ptr<foo> p1(new foo(1));
arr[0] = std::move(p1);
std::unique_ptr<foo> p2(new foo(2));
arr[1] = std::move(p2);
std::unique_ptr<foo> p3(new foo(3));
arr[2] = std::move(p3);
// print array
for(auto &i : arr) if(i != nullptr) std::cout << i->getid() << " ";
std::cout << std::endl;
// reset first position (i.e., remove element at position 0)
arr[0].reset();
// print array
for(auto &i : arr) if(i != nullptr) std::cout << i->getid() << " ";
std::cout << std::endl;
return 0;
}
LIVE DEMO
I have a vector with each element being a pair. I am confused with the syntax. Can someone please tell me how to iterate over each vector and in turn each element of pair to access the class.
std::vector<std::pair<MyClass *, MyClass *>> VectorOfPairs;
Also, please note, I will be passing the values in between the function, hence VectorOfPairs with be passed by pointer that is *VectorOfPairs in some places of my code.
Appreciate your help. Thanks
This should work (assuming you have a C++11 compatible compiler)
for ( auto it = VectorOfPairs.begin(); it != VectorOfPairs.end(); it++ )
{
// To get hold of the class pointers:
auto pClass1 = it->first;
auto pClass2 = it->second;
}
If you don't have auto you'll have to use std::vector<std::pair<MyClass *, MyClass *>>::iterator instead.
Here is a sample. Note I'm using a typedef to alias that long, ugly typename:
typedef std::vector<std::pair<MyClass*, MyClass*> > MyClassPairs;
for( MyClassPairs::iterator it = VectorOfPairs.begin(); it != VectorOfPairs.end(); ++it )
{
MyClass* p_a = it->first;
MyClass* p_b = it->second;
}
Yet another option if you have a C++11 compliant compiler is using range based for loops
for( auto const& v : VectorOfPairs ) {
// v is a reference to a vector element
v.first->foo();
v.second->bar();
}
You can access the elements of pairs inside vector in C++17 in a following style by combining range-based for loop and structured bindings. Example:
for (auto& [x, y] : pts) {
cin >> x >> y;
}
where pts is a vector of pairs. & is used to make formal "uniquely-named variable" e of structured binding a reference so that x and y referring to subobjects of e refer to original pair inside pts, which can be modified this way (e.g. cin can be used to input to it). Without &, e would be a copy (to subobjects of which x and y again refer). Example using your VectorOfPairs:
for (auto [pFirst, pSecond] : VectorOfPairs ) {
// ...
}
Also you can make e a reference to const when modification through structured binding is not needed and you want to avoid potentially expensive copy of a pair (though this should not be a problem in your case since pair object consisting of 2 pointers is pretty small and cheap to copy). Example:
for (const auto& [pFirst, pSecond] : VectorOfPairs ) {
// ...
}