Here is the code from the book
LargeType randomItem1( const vector<LargeType> & arr )
{
return arr[ randomInt( 0, arr.size( )-1)];
}
const LargeType & randomItem2( const vector<LargeType> & arr )
{
return arr[ randomInt( 0, arr.size( )-1)];
}
vector<LargeType> vec;
...
LargeType item1 = randomItem1( vec );// copy
LargeType item2 = randomItem2( vec );// copy
const LargeType & item3 = randomItem2( vec ); // no copy
vector<int> partialSum( const vector<int> & arr )
{
vector<int> result( arr.size( ) );
result[ 0 ] = arr[ 0 ];
for( int i = 1; i < arr.size( ); ++i )
{
result[ i ] = result[ i-1]+ arr[ i ];
}
return result;
}
vector<int> vec;
...
vector<int> sums = partialSum( vec ); // Copy in old C++; move in C++11
The book says LargeType randomItem1( const vector<LargeType> & arr ) does not call move semantics while vector<int> partialSum( const vector<int> & arr ) does. Why is this happening?
I understand that return arr[ randomInt( 0, arr.size( )-1)]; is an lvalue since arr itself is reference of object but isn't result an object too? the book says return result is temporary, however it is declared at line 3 at second code box.
want to know why return result is temporary even if it is declared and have name.
The fucntion randomItem1 does not own arr, which means it is not allowed to move arr[ randomInt( 0, arr.size( )-1)] out of the function.
In partialSum the function owns result so it is free to move it out of the function once the function ends.
The rule is that all function local variables can be treated as rvalues for the purpose of the return statement and only are considered an lvalue if no constructor can be found when considered as an rvalue.
In addition to what NathanOliver said, vector<int> sums = partialSum( vec ); may result in neither copy nor move because of copy elision.
Related
I've just started learning C++ and I'm trying how std::vector works.
I have this test program:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> element1 = { 1, 2,3 };
std::vector<int> element2 = { 4, 5, 6 };
std::vector<std::vector<int>> lista = { element1, element2 };
std::vector<int> var = lista.at(0);
for (std::vector<int>::const_iterator i = var.begin(); i != var.end(); ++i)
std::cout << *i << ' ';
std::cout << std::endl;
var[0] = 22;
for (std::vector<int>::const_iterator i = var.begin(); i != var.end(); ++i)
std::cout << *i << ' ';
std::cout << std::endl;
for (std::vector<int>::const_iterator i = lista.at(0).begin(); i != lista.at(0).end(); ++i)
std::cout << *i << ' ';
std::cout << std::endl;
return 0;
}
That outputs:
1 2 3
22 2 3
1 2 3
I think that at operator doesn't return a reference (but maybe I'm wrong), so I think it returns a new vector, isn't it?
But, if I want to get a reference, how can I do it?
UPDATE:
And... if I want to get in lista the references of element1 and element2 instead of a copy?
at returns a reference (and a const reference for the const version).
Your issue is that you are taking an explicit value copy in your code with std::vector<int> var = lista.at(0);. The obvious fix is auto& var = lista.at(0);.
Finally, if you wish to avoid a value copy of element1 and element2, you can remove them and write
std::vector<std::vector<int>> lista = { { 1, 2,3 }, { 4, 5, 6 } };
instead.
Reference: http://en.cppreference.com/w/cpp/container/vector/at
at returns a reference.
You store it in a copy here std::vector<int> var = lista.at(0);
You might do std::vector<int>& var = lista.at(0); to get reference.
I think that at operator doesn't return a reference (but maybe I'm wrong)
You're wrong indeed. vector::at returns a reference, as shown in the declaration:
reference at( size_type pos );
const_reference at( size_type pos ) const;
However, std::vector<int> var is not a reference, and you copy initialize it from the returned reference.
But, if I want to get a reference, how can I do it?
To get a reference, you need a reference variable where you can capture the reference returned by at:
std::vector<int>& var = lista.at(0);
// ^ a reference
And also here, std::vector<std::vector<int>> lista = { element1, element2 };, I think there is a copy of element1 and element2 in lista vector.
That's right.
If I don't want to create a copy of element1 and element2, what do I have to do?
If you don't want to store (copies of) vectors in the outer vector, then you need to store something else. You cannot store references in containers, but you can store std::reference_wrappers or pointers. For example:
std::vector<std::vector<int>*> lista = { &element1, &element2 };
You can then get a reference to the pointed vector using the indirection operator.
It's not clear from your example what you're trying to do, perhaps it might make sense to have a vector of vectors, and let element1 and element2 be references instead:
std::vector<std::vector<int>> lista = {
{ 1, 2, 3 },
{ 4, 5, 6 },
};
std::vector<int>& element1 = lista[0];
std::vector<int>& element2 = lista[1];
If you only want to avoid copying contents of the subvectors, and if you don't intend to use element1 and element2 afterwards, then there is another way: You can move construct the subvectors of lista:
std::vector<std::vector<int>> lista = {
std::move(element1),
std::move(element2),
};
// element1 and elemenet2 are now in an unspecified state
var is not a reference, its just another variable like b below.
int a = 5;
int b = a;
int &bref = a;
b=6;
cout<<a<<endl; // a is still 5
bref = 6;
cout<<a<<endl; // a is now 6
What you want is bref and not b ie
std::vector<int> &var = lista.at(0);
So I have a programming assignment where they supply us with the header file which contains:
class SEQ{
private:
...// stuff
public:
...//constructor
string operator ( ) ( ) {
string tmp = id; int i = nd - 1;
if ( id [ i ] < '9' ) id [ i ]++;
else {
id [ i ] = '1'; bool flag = true;
for ( i--; i >= 0 && flag; i-- )
if ( id [ i ] < 'Z' ) { id [ i ]++; flag = false; }
else id [ i ] = 'A';
}
return tmp;
}
}
I am supposed to use this with std::generate on an std::vector. However, the function never gets called. I have tried writing it these ways:
vector<string> v;
for (int i = v.size(); i < in.N; i++) v.push_back("");
generate(v.begin(), v.end(), SEQ); // compiler error
generate(v.begin(), v.end(), SEQ()); // no error but does nothing
SEQ seq; // declare an instance
generate(v.begin(), v.end(), seq); // no error but does nothing
generate(v.begin(), v.end(), seq()); // compiler error algorithm line 1527 does not evaluate to a function that takes 0 arguments
I am assuming the header file they gave me does not contain any errors. How am I supposed to write this so that the function gets called?
generate takes a function pointer or a reference to an instance of a functor. The following two calls are correct. They are no-ops if the vector is empty.
// pass a default-constructed temporary instance
generate(v.begin(), v.end(), SEQ{});
// pass a named instance
SEQ seq;
generate(v.begin(), v.end(), seq);
The following works:
#include <algorithm>
#include <vector>
#include <cassert>
int main()
{
std::vector<size_t> v(10);
auto seq = [a = 0]() mutable { return a++; };
std::generate(v.begin(), v.end(), seq);
assert(v.begin() != v.end());
for (size_t i = 0; i < v.size(); ++i)
assert(v[i] == i);
}
Consider this unit test:
std::bitset<8> temp( "11010100" );
reverseBitSet( temp );
CPPUNIT_ASSERT( temp == std::bitset<8>( "00101011" ) );
This implementation works:
template<size_t _Count> static inline void reverseBitSet( std::bitset<_Count>& bitset )
{
bool val;
for ( size_t pos = 0; pos < _Count/2; ++pos )
{
val = bitset[pos];
bitset[pos] = bitset[_Count-pos-1];
bitset[_Count-pos-1] = val;
}
}
While this one does not:
template<size_t _Count> static inline void reverseBitSet( std::bitset<_Count>& bitset )
{
for ( size_t pos = 0; pos < _Count/2; ++pos )
{
std::swap( bitset[pos], bitset[_Count-pos-1] );
}
}
Result is "11011011" instead of "00101011"
Why is swap doing it wrong?
This:
std::swap( bitset[pos], bitset[_Count-pos-1] );
should actual fail to compile. operator[] for a std::bitset doesn't return a reference, it returns a proxy object. That proxy object isn't an lvalue, so it cannot bind to the T& in std::swap. I'm assuming the fact that it compiles at all means that you're using MSVC which has an extension that allows binding temporaries to non-const references - at which point you're probably just swapping the proxies and not what the proxies are actually referring to.
Side-note: The name _Count is reserved by the standard, as is any other name which begins with an _ followed by a capital letter.
I have the following code that intends to create an array, but without default initialization of its objects. I would like to forward perfectly to placement new, which seems to happen, but I find that the objects' destructor is called inside the emplace function.
#include <iostream>
#include <memory> // std::uninitialized_copy, std::allocator...
#include <utility> // std::move...
#include <bitset>
struct Int {
int i;
Int ( ) : i ( -1 ) { std::cout << "default constructed\n"; }
Int ( const int i_ ) : i ( i_ ) { std::cout << i << " constructed\n"; }
Int ( Int && int_ ) : i ( std::move ( int_.i ) ) { std::cout << i << " move constructed\n"; }
Int ( const Int & int_ ) : i ( int_.i ) { std::cout << i << " copy constructed\n"; }
~Int ( ) { std::cout << i << " destructed\n"; i = -1; }
};
template <typename T, size_t S = 64>
class NoInitArray {
std::bitset<S> m_used;
T *m_array = reinterpret_cast < T* > ( ::operator new ( sizeof ( T ) * S ) );
public:
T const &operator [ ] ( const size_t idx_ ) const {
return m_array [ idx_ ];
}
NoInitArray ( ) { }
~NoInitArray ( ) {
for ( size_t idx = 0; idx < S; ++idx ) {
if ( m_used [ idx ] ) {
reinterpret_cast< const T* > ( m_array + idx )->~T ( );
}
}
}
template<typename ...Args>
void emplace ( const size_t idx_, Args &&... value_ ) {
std::cout << "start emplace\n";
m_used [ idx_ ] = 1;
new ( m_array + idx_ ) T ( std::forward<T> ( value_ ) ... );
std::cout << "end emplace\n";
}
};
int main ( ) {
NoInitArray<Int> nia;
nia.emplace ( 0, 0 );
nia.emplace ( 1, 1 );
std::cout << nia [ 1 ].i << std::endl;
nia.emplace ( 2, 2 );
return 0;
}
The result of running this program is as follows:
start emplace
0 constructed
0 move constructed
0 destructed
end emplace
start emplace
1 constructed
1 move constructed
1 destructed
end emplace
1
start emplace
2 constructed
2 move constructed
2 destructed
end emplace
0 destructed
1 destructed
2 destructed
It shows that the objects are constructed once and destructed twice (which obviously is UB), once inside the emplace function, and then once at destruction of the NoInitArray.
The question is "Why is the destructor of my Int object called inside the emplace function"?
Compiler, latest Clang/LLVM on Windhoze.
EDIT1: I've added move and copy constructors to the Int struct, now the count matches, i.e. 2 constructions and 2 destructions.
EDIT2: Changing the Placement New line from new ( m_array + idx_ ) T ( std::forward<T> ( value_ ) ... ); to new ( m_array + idx_ ) T ( value_ ... ); avoids the superfluous construction/destruction, without the need for a move constructor.
EDIT3: Just for future readers. As per above, the ~NoInitArray() leaks memory. Calling delete on m_array is bad news as well as this calls (in Clang/LLVM) the destructor of m_array [ 0 ] (but as far as I've understood now, that is in no way guaranteed, i.e. UB). std::malloc/std::free seems to be the way to go, but some say that if you do that all hell will break lose, and one may lose a leg.
"It shows that the objects are constructed once and destructed twice" is not true. The output X move constructed should be included as one construction so the constructions are twice.
The line
new ( m_array + idx_ ) T ( std::forward<T> ( value_ ) ... );
should be
new ( m_array + idx_ ) T ( std::forward<Args&&> ( value_ )... );
std::forward<T>(value_) calls the constructor when T=Int, and this temporary object is moved, so there is an extra move constructor call.
EDIT
In your edit 2 you replace the line without std::forward anymore. In this case, OK, but the differences emerge when you call the emplace like this
nia.emplace ( 0, Int(0) );
Without std::forward, new T(value_...) would call the copy constructor, while new T(std::forward<Args&&>(value_)...) would call the move constructor.
EDIT-2
It should be new T(std::forward<Args>(value_)...). Thanks to #Constantin Baranov.
I think the constructor and destructor are called in the step: std::forward<T> ( value_ ) in new ( m_array + idx_ ) T ( std::forward<T> ( value_ ) ... ).
The std::forward<T>(value_) will create a temp value T.
I do have a cpp class in an otherwise iOS/ObjC project. It uses the following map:
std::map <std::string, int> testMap;
I do know that I can "count" the number of appearances of a given key in that map via testMap.count. But how do I count the number of appearances of a given value in that map?
e.g. suppose to have the following map:
<Anna, 5>
<Brian, 4>
<Cesar, 4>
<Danny, 3>
--> So if I look for the number of value "4" the function should return 2, for values "5" and "3" respectively it should return 1 for each, otherwise 0...
Thanks in advance!
The easiest way is probably to use std::count_if with an appropriate lambda:
int value = 4; // or something else
std::count_if(std::begin(testMap),
std::end (testMap),
[value](std::pair<std::string, int> const &p) {
return p.second == value;
});
This simply walks through the map and counts all elements that fit the predicate.
It can be simply done using the range based for statement:)
size_t count = 0;
int value = 4;
for ( auto &p : testMap ) count += p.second == value;
Sometimes using the range based for statement looks more readable than using standard algorithm std::count_if.:)
On the other hand if this operation is used several times then it will be better to use the algorithm. For example
int value = 4;
size_t n = std::count_if( std::begin( testMap ), std::end( testMap ),
[&value]( const std::pair<const std::string, int> &p )
{
return p.second == value;
} );
Also you could define the lambda separately from calls of the algorithm
int value;
size_t n;
auto IsEqual = [&value]( const std::pair<const std::string, int> &p )
{
return p.second == value;
};
value = 4;
n = std::count_if( std::begin( testMap ), std::end( testMap ), IsEqual );
//...
value = 5;
n = std::count_if( std::begin( testMap ), std::end( testMap ), IsEqual );