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.
