I need to convert std::list< customStruct >
to std::vector<std::string>
.
Is it possible to move all data from the customStruct::s_
into the vector of stings?
customStruct
{
std::string s_;
};
Is it work for std::transform
and std::make_move_iterator
?
Is this example correct? Will it really move strings?
std::list< customStruct > list;
std::vector< std::string> vt;
vt.reserve( list.size() );
std::transform( std::make_move_iterator( list.begin() ), std::make_move_iterator( list.end() ),
vt.begin(), [](const auto& el ) -> std::string
{
return std::move( el.s_ );
} );
CodePudding user response:
Since your lambda takes [](const auto& el )
by const reference, the el
is declared as const customStruct&
, so el.s_
will be a const std::string
(and the function will copy). You can instead take customStruct&&
(or by universal reference auto&&
). You can also not use move iterators and instead have your lambda take non-const lvalue references.
You also can't transform into vt.begin()
because this will write to uninitailized elements (their memory only reserved, they are not actually constructed). Use std::back_inserter(vt)
instead.
One example:
std::list< customStruct > list = /* something */;
std::vector<std::string> vt;
vt.reserve(list.size());
std::transform(list.begin(), list.end(), std::back_inserter(vt), [](auto& el) -> std::string&& {
return std::move(el.s_);
});
CodePudding user response:
You should resize
the vector before transforming into it. reserve
only allocates capacity and then transform
assigns to non-existing vector elements. Thats undefined behavior. Alternatively stay with reserve
and use a back_inserter
.
To see if it actually moves the elements you can add some output:
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <algorithm>
struct moveable {
moveable() {}
moveable(moveable&&){ std::cout << "move ctr\n"; }
moveable& operator=(const moveable&){ return *this;}
moveable(const moveable&) { std::cout << "copy ctr\n"; }
};
struct customStruct
{
moveable m;
std::string s_;
};
int main() {
std::list< customStruct > list;
list.push_back({});
list.push_back({});
list.push_back({});
std::vector< moveable > vt;
vt.resize( list.size() );
std::cout << "transform:\n";
std::transform( std::make_move_iterator( list.begin() ), std::make_move_iterator( list.end() ),
vt.begin(), [](const auto& el ) -> moveable
{
return std::move( el.m );
} );
std::cout << "transform2\n";
std::transform( std::make_move_iterator( list.begin() ), std::make_move_iterator( list.end() ),
vt.begin(), [](auto&& el ) -> moveable
{
return std::move( el.m );
} );
}
move ctr
move ctr
move ctr
transform:
copy ctr
copy ctr
copy ctr
transform2
move ctr
move ctr
move ctr
You cannot move from a const&
thats why your code is not moving.