简体   繁体   中英

c++ - std::string and move_iterator

I was writing a tokenizer that would split a string and put each of the fields inside a vector . My idea was to use string::find repeatedly. Instead of using a temporary string object, I used move_iterator s, as I supposed the original string would see its characters stolen as the algorithm processed it. But it didn't happen.

This is an example code that demonstrates what I'm talking about:

#include <vector>
#include <string>
#include <iostream>

using namespace std;

void
print_strings
    ( const vector<string> & v )
{
    unsigned int i = 1;
    for ( const auto & s : v )
        cout << "#" << i++ << "\t: \"" << s << "\"" << endl;
    return;
}

int
main
    ( void )
{
    string base( "hello, this is an example string, I like icescreams" );

    /* Vector to populate with strings */
    vector<string> v;

    /* 1: a copy of 'base' */
    v.emplace_back( base );
    /* 2: a copy of 'base' using iterators */
    v.emplace_back( base.begin() , base.end() );
    /* 3: a string that I think _should_ move from 'base' */
    v.emplace_back( make_move_iterator(base.begin()) , make_move_iterator(base.end()) );

    /* Print the strings twice so that we
     * can see if something has changed. */
    print_strings( v );
    print_strings( v );

    return 0;
}

When compiled with g++ -std=c++11 -Wall -Wextra -Werror -O2 , it shows no warnings.

My guessings are that string 's constructors, in its range version, always copies from the specified range. As I'm not sure, I'd like to be sure and, of course, to see any workarounds you had used.

Best regards, Kalrish

Iterators don't know anything about the container.

A move_iterator can't magically move from the string. It can't only move from its underlying element, that's a single char and moving from a char is the same as copying it. You need to use std::move(base) .

#include <vector>
#include <string>
#include <iostream>

using namespace std;

void
print_strings
    ( const vector<string> & v )
{
    unsigned int i = 1;
    for ( const auto & s : v )
        cout << "#" << i++ << "\t: \"" << s << "\"" << endl;
    return;
}

int
main
    ( void )
{
    string base( "hello, this is an example string, I like icescreams" );

    /* Vector to populate with strings */
    vector<string> v;

    /* 1: a copy of 'base' */
    v.emplace_back( base );
    /* 2: a copy of 'base' using iterators */
    v.emplace_back( base.begin() , base.end() );
    /* 3: a string that I think _should_ move from 'base' */

    std::cout << base << '\n'; // base is still untouched here

    v.emplace_back( std::move(base) ); // now it'll be moved from

    print_strings( v );
    std::cout << "base: " << base << "/base\n"; // base is empty
    return 0;
}

See it live here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM