Prototype in C++ - c++

Would the answer just be C and E? I am confused as to if bool &status can be passed by reference?
You want a function that reads in data about a movie from a specified file and returns a Movie object, either via a return value or via a parameter. It should also return some indication of success or failure either via a return value or via a parameter. Which of the following would be possible prototype choices for the above requirements? Select all that apply.
A. Movie readMovie(string filename);
B. bool readMovie(string filename, Movie m);
C. Movie readMovie(string filename, bool &status);
D. bool readMovie(string filename, const Movie &m);
E. bool readMovie(string filename, Movie &m);
F. Movie readMovie(string filename, bool status);

All of them can work:
A. if Movie itself can have a well known bad value (equivalent to end, EOF or NULL), or a member to check whether it's in a good state, this is fine:
Movie readMovie(string filename);
Movie m = readMovie(filename);
if (m.good() || m != Movie::InvalidMovie || ... ) {
however, I suspect the questioner thinks this doesn't count as indicating success via a return value ...
B. if Movie is typedef'd to a pointer, or a shared_ptr, or if Movie is a lightweight wrapper for a refcounted MovieImpl object (for example), this is fine (because the caller's shared state is mutated via readMovie's copy of the wrapper)
bool readMovie(string filename, Movie m);
however, I suspect the questioner thinks this doesn't count as indicating success via a ... parameter. (NB. A's Movie could also be a typedef, smart pointer or other handle-body style thing).
C. this is definitely fine (and even the questioner knows it)
Movie readMovie(string filename, bool &status);
D. same constraints as B
bool readMovie(string filename, const Movie &m);
E. fine
bool readMovie(string filename, Movie &m);
F. stupid: this can work in the same was as A, but the status param is useless and misleading. So, I'm certain the questioner doesn't expect this to work:
Movie readMovie(string filename, bool status);
So, what can really be made to work: all of them.
What the questioner probably wants to hear: C, E.
What you should be looking at:
designing clear, expressive, efficient interfaces that are easy to use correctly (none of the above fit this, IMO)
appropriate use of exceptions instead of return codes (if failure is genuinely exceptional)
passing that string filename by const reference
getting a better teacher.

Let's see:
A provides no boolean indication of success. False.
B is passing Movie by value, so there's no way it will get returned. False.
C returns a movie, and the bool is passed by ref so it will get modified. True.
(skip)
E is the opposite of C, so it will work too. True.
(back to) D is the same as E, except it will be a const Movie this may or may not be appropriate. True?
F is the opposite of B, and fails for the same reason. False.
It's not a terribly clear question, and I would indicate my reasoning for my answers on the test/homework.

A movie is a big thing, so it should be allocated dynamically.
Therefore, use a smart pointer.
The code below demonstrates/proves how each and every proposed function signature supports returning a loaded movie and checking whether it succeeded or failed, with the most natural interpretation of the information provided (in particular, that a "movie" is a movie).
Note that the signatures in the question are all examples of Very Bad Design™.
The signature shown in namespace right in the code below is however OK:
It supports Windows filenames in general.
It ensures that if the load fails, the calling code has no movie object to (erroneously) play with, and this is done by throwing an exception to indicate failure.
It passes the string by reference to const (for efficiency and as a general good habit).
#include <memory> // std::shared_ptr
#include <new> // std::nothrow
#include <stdexcept> // std::runtime_error
#include <string> // std::string
class MovieData
{
// Whatever
};
// *** A movie is a big thing, so it should be allocated dynamically. ***
// *** Therefore, use a smart pointer. ***
//
typedef std::shared_ptr< MovieData > Movie;
namespace a {
using std::string;
using std::nothrow;
Movie readMovie(string filename)
{
return 0?0
: filename == "succeed"? Movie( ::new(nothrow) MovieData )
: Movie();
}
bool test( string const& filepath )
{
Movie const m = readMovie( filepath );
return (m != nullptr);
}
}
namespace b {
using std::string;
using std::nothrow;
bool readMovie(string filename, Movie m)
{
if( filename != "succeed" || m == nullptr )
{
return false;
}
*m = MovieData();
return true;
}
bool test( string const& filepath )
{
Movie const m( ::new(nothrow) MovieData );
return readMovie( filepath, m );
}
}
namespace c {
using std::string;
using std::nothrow;
Movie readMovie(string filename, bool &status)
{
status = false;
if( filename != "succeed" )
{
return Movie();
}
Movie const result( ::new(nothrow) MovieData );
status = true;
return result;
}
bool test( string const& filepath )
{
bool result = false;
readMovie( filepath, result );
return result;
}
}
namespace d {
using std::string;
using std::nothrow;
bool readMovie(string filename, const Movie &m)
{
if( filename != "succeed" || m == nullptr )
{
return false;
}
*m = MovieData();
return true;
}
bool test( string const& filepath )
{
Movie const m( ::new(nothrow) MovieData );
return readMovie( filepath, m );
}
}
namespace e {
using std::string;
using std::nothrow;
bool readMovie(string filename, Movie &m)
{
if( filename != "succeed" )
{
return false;
}
m.reset( ::new(nothrow) MovieData );
return (m != nullptr);
}
bool test( string const& filepath )
{
Movie m;
return readMovie( filepath, m );
}
}
namespace f {
using std::string;
using std::nothrow;
Movie readMovie(string filename, bool status)
{
(void) status; struct status; // Intentionally not used.
if( filename != "succeed" )
{
return Movie();
}
return Movie( ::new(nothrow) MovieData );
}
bool test( string const& filepath )
{
return (readMovie( filepath, bool() ) != nullptr);
}
}
namespace right {
using std::wstring; // Using wide string supports nearly all Windows filenames.
using std::runtime_error;
Movie readMovie( wstring const& filepath )
{
if( filepath != L"succeed" )
{
throw std::runtime_error( "right::readMovie: failed because ..." );
}
return Movie( new MovieData );
}
bool test( wstring const& filepath )
{
try
{
readMovie( filepath );
return true;
}
catch( ... )
{
return false;
}
}
}
#define TEST( name, filename ) \
wcout << #name "::readMovie" << "( " << #filename << " ) " \
<< (name ::test( filename )? "succeeded" : "failed") << "." << endl;
#include <iostream> // std::wcout, std::endl
int main()
{
using std::wcout; using std::endl; using std::boolalpha;
wcout << boolalpha;
TEST( a, "succeed" );
TEST( a, "fail" );
wcout << endl;
TEST( b, "succeed" );
TEST( b, "fail" );
wcout << endl;
TEST( c, "succeed" );
TEST( c, "fail" );
wcout << endl;
TEST( d, "succeed" );
TEST( d, "fail" );
wcout << endl;
TEST( e, "succeed" );
TEST( e, "fail" );
wcout << endl;
TEST( f, "succeed" );
TEST( f, "fail" );
wcout << endl;
TEST( right, L"succeed" );
TEST( right, L"fail" );
}
Output (test results):
a::readMovie( "succeed" ) succeeded.
a::readMovie( "fail" ) failed.
b::readMovie( "succeed" ) succeeded.
b::readMovie( "fail" ) failed.
c::readMovie( "succeed" ) succeeded.
c::readMovie( "fail" ) failed.
d::readMovie( "succeed" ) succeeded.
d::readMovie( "fail" ) failed.
e::readMovie( "succeed" ) succeeded.
e::readMovie( "fail" ) failed.
f::readMovie( "succeed" ) succeeded.
f::readMovie( "fail" ) failed.
right::readMovie( L"succeed" ) succeeded.
right::readMovie( L"fail" ) failed.

Related

Template method inside a class

I have a class called time which has day, month and year.
I have a problem with returning the right value in my method, where it, depending on what we enter as a string "s" it should return an int value from one of those 3 fields.
So, for example, if I want to get days in my date I should call the function d["day"].
My question is, Is there something wrong with my code here? And, what should I put instead of
int operator[] (string s)
{
if (s == "day" || s == "month" || s == "year")
{
return ? ? ? ;
}
}
From the explanation, if I understood correctly, you need the following. You need to return appropriate member (i.e. either day or month or year) according to the string match. (Assuming that you have mDay, mMonth, and mYear as int eger members in your Date class)
int operator[] (std::string const& s)
{
if (s == "day") return mDay;
if (s == "month") return mMonth;
if (s == "year") return mYear;
// default return
return -1;
}
or alternatively using a switch statement
// provide a enum for day-month-year
enum class DateType{ day, month, year};
int operator[] (DateType type)
{
switch (type)
{
case DateType::day: return mDay;
case DateType::month: return mMonth;
case DateType::year: return mYear;
default: return -1;
}
}
A dimple way is to define the date as an array of three elements instead of declaring three separate data members.
In this case the operator can look the following way as it is shown in the demonstrative program below.
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <stdexcept>
class MyDate
{
private:
unsigned int date[3] = { 26, 12, 2019 };
public:
unsigned int operator []( const std::string &s ) const
{
const char *date_names[] = { "day", "month", "year" };
auto it = std::find( std::begin( date_names ), std::end( date_names ), s );
if ( it == std::end( date_names ) )
{
throw std::out_of_range( "Invalid index." );
}
else
{
return date[std::distance( std::begin( date_names ), it )];
}
}
};
int main()
{
MyDate date;
std::cout << date["day"] << '.' << date["month"] << '.' << date["year"] << '\n';
return 0;
}
The program output is
26.12.2019
Otherwise you should use either if-else statements or a switch statement within the operator.

C++ Brute Force attack function does not return results

so I'm currently working on a brute force attacker project in C++. I've managed to get it working, but one problem that I'm facing is that if the program actually managed to get a correct guess, the function still goes on. I think the problem is that the program fails to return a guess. Take a look at my code:
(Sorry for the mess, by the way, I'm not that experienced in C++ - I used to code in Python/JS.)
#include <iostream>
#include <cstdlib>
#include <string>
std::string chars = "abcdefghijklmnopqrstuvwxyz";
std::string iterateStr(std::string s, std::string guess, int pos);
std::string crack(std::string s);
std::string iterateChar(std::string s, std::string guess, int pos);
int main() {
crack("bb");
return EXIT_SUCCESS;
}
// this function iterates through the letters of the alphabet
std::string iterateChar(std::string s, std::string guess, int pos) {
for(int i = 0; i < chars.length(); i++) {
// sets the char to a certain letter from the chars variable
guess[pos] = chars[i];
// if the position reaches the end of the string
if(pos == s.length()) {
if(guess.compare(s) == 0) {
break;
}
} else {
// else, recursively call the function
std::cout << guess << " : " << s << std::endl;
iterateChar(s, guess, pos+1);
}
}
return guess;
}
// this function iterates through the characters in the string
std::string iterateStr(std::string s, std::string guess, int pos) {
for(int i = 0; i < s.length(); i++) {
guess = iterateChar(s, guess, i);
if(s.compare(guess) == 0) {
return guess;
}
}
return guess;
}
std::string crack(std::string s) {
int len = s.length();
std::string newS(len, 'a');
std::string newGuess;
newGuess = iterateStr(s, newS, 0);
return newGuess;
}
Edit : Updated code.
The main flaw in the posted code is that the recursive function returns a string (the guessed password) without a clear indication for the caller that the password was found.
Passing around all the strings by value, is also a potential efficiency problem, but the OP should be worried by snippets like this:
guess[pos] = chars[i]; // 'chars' contains the alphabet
if(pos == s.length()) {
if(guess.compare(s) == 0) {
break;
}
}
Where guess and s are strings of the same length. If that length is 2 (OP's last example), guess[2] is outside the bounds, but the successive call to guess.compare(s) will compare only the two chars "inside".
The loop inside iterateStr does nothing useful too, and the pos parameter is unused.
Rather than fixing this attempt, it may be better to rewrite it from scratch
#include <iostream>
#include <string>
#include <utility>
// Sets up the variable and start the brute force search
template <class Predicate>
auto crack(std::string const &src, size_t length, Predicate is_correct)
-> std::pair<bool, std::string>;
// Implements the brute force search in a single recursive function. It uses a
// lambda to check the password, instead of passing it directly
template <class Predicate>
bool recursive_search(std::string const &src, std::string &guess, size_t pos,
Predicate is_correct);
// Helper function, for testing purpouse
void test_cracker(std::string const &alphabet, std::string const &password);
int main()
{
test_cracker("abcdefghijklmnopqrstuvwxyz", "dance");
test_cracker("abcdefghijklmnopqrstuvwxyz ", "go on");
test_cracker("0123456789", "42");
test_cracker("0123456789", "one"); // <- 'Password not found.'
}
void test_cracker(std::string const &alphabet, std::string const &password)
{
auto [found, pwd] = crack(alphabet, password.length(),
[&password] (std::string const &guess) { return guess == password; });
std::cout << (found ? pwd : "Password not found.") << '\n';
}
// Brute force recursive search
template <class Predicate>
bool recursive_search(std::string const &src, std::string &guess, size_t pos,
Predicate is_correct)
{
if ( pos + 1 == guess.size() )
{
for (auto const ch : src)
{
guess[pos] = ch;
if ( is_correct(guess) )
return true;
}
}
else
{
for (auto const ch : src)
{
guess[pos] = ch;
if ( recursive_search(src, guess, pos + 1, is_correct) )
return true;
}
}
return false;
}
template <class Predicate>
auto crack(std::string const &src, size_t length, Predicate is_correct)
-> std::pair<bool, std::string>
{
if ( src.empty() )
return { length == 0 && is_correct(src), src };
std::string guess(length, src[0]);
return { recursive_search(src, guess, 0, is_correct), guess };
}
I've tried your code even with the modified version of your iterateStr() function. I used the word abduct as it is quicker to search for. When stepping through the debugger I noticed that your iterateChar() function was not returning when a match was found. Also I noticed that the length of string s being passed in was 6 however the guess string that is being updated on each iteration had a length of 7. You might want to step through your code and check this out.
For example at on specific iteration the s string contains: abduct but the guess string contains aaaabjz then on the next iteration the guess string contains aaaabkz. This might be your concerning issue of why the loop or function continues even when you think a match is found.
The difference in lengths here could be your culprit.
Also when stepping through your modified code:
for ( size_t i = 0; i < s.length(); i++ ) {
guess = iterCh( s, guess, i );
std::cout << "in the iterStr loop\n";
if ( guess.compare( s ) == 0 ) {
return guess;
}
}
return guess;
in your iterateStr() function the recursion always calls guess = iterCh( s, guess, i ); and the code never prints in the iterStr loop\n";. Your iterateChar function is completing through the entire string or sequence of characters never finding and return a match. I even tried the word abs as it is easier and quicker to step through the debugger and I'm getting the same kind of results.

Templated operator<< isn't being recognized

I created a class called SkipToChar that's supposed to be able to be used as follows:
std::ostringstream oss;
oss << "Hello," << SkipToChar(7) << "world!" << std::endl;
Which would print "Hello, world!" (notice the space.) Basically it's supposed to skip to the character at the specified index using spaces. But apparently the compiler doesn't recognize the operator<< I created for it. Interestingly, calling operator<< explicitly, even without giving any template parameters (like operator<<(oss, SkipToChar(7)); works fine; it just doesn't work if I actual
Here's my code:
#include <iostream>
#include <sstream>
template <typename _Elem>
struct basic_SkipToChar
{
typename std::basic_string<_Elem>::size_type pos;
basic_SkipToChar(typename std::basic_string<_Elem>::size_type position)
{
pos = position;
}
};
template <typename _Elem>
inline std::basic_ostringstream<_Elem> &operator<<(std::basic_ostringstream<_Elem> &oss, const basic_SkipToChar<_Elem> &skip)
{
typename std::basic_string<_Elem>::size_type length = oss.str().length();
for (typename std::basic_string<_Elem>::size_type i = length; i < skip.pos; i++) {
oss << (_Elem)' ';
}
return oss;
}
typedef basic_SkipToChar<char> SkipToChar;
typedef basic_SkipToChar<wchar_t> WSkipToChar;
int main(int argc, char *argv[])
{
std::ostringstream oss;
/*ERROR*/ oss << "Hello," << SkipToChar(8) << "world!" << std::endl;
std::cout << oss.str();
return 0;
}
It gives me the following error when I try to compile it:
error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'basic_SkipToChar<char>' (or there is no acceptable conversion)
I marked the line the error is on with a comment. What's going wrong here?
oss << "Hello," returns std::basic_ostream<char> (it loses the string part).
So your method doesn't match (expect std::basic_ostringstream but got std::basic_ostream<char>).
As Jarod42 points out, the return type of all of the built-in
operator<< is std::ostream&. This is a basic principle of
how streams operator; except for the actual sink or source, the
stream should be indifferent as to where the data is going to or
coming from.
It's possible to provide manipulators which only work for one
type of stream, or do different things for different types of
streams, by using a dynamic_cast in the manipulator:
std::ostream&
operator<<( std::ostream& dest, SkipToChar const& manip )
{
std::ostringstream* d = dynamic_cast<std::ostringstream*>( &dest );
if ( d != nullptr ) {
// ...
}
return dest;
}
In general, however, this is a very bad idea; clients will be
very surprised that outputting to a string results in different
text than outputting to a file.
What you seem to be trying to do is to more or less emulate
a form of tabbing. The best way to do this is to use
a filtering output streambuf, which keeps track of where you are
in the line, and can be inserted between the std::ostream and
the actual sink regardless of the type of stream:
class TabbingOutputStreambuf : public std::streambuf
{
std::streambuf* myDest;
std::ostream* myOwner;
int myInLineCount;
public:
TabbingOutputStreambuf( std::streambuf* dest )
: myDest( dest )
, myOwner( nullptr )
, myInLineCount( 0 )
{
}
TabbingOutputStreambuf( std::ostream& dest )
: myDest( dest.rdbuf() )
, myOwner( &dest )
, myInLineCount( 0 )
{
myOwner.rdbuf( this );
}
~TabbingOutputStreambuf()
{
if ( myOwner != nullptr ) {
myOwner->rdbuf( myDest );
}
}
int overflow( int ch ) override
{
if ( ch == '\n' ) {
myInLineCount = 0;
} else {
++ myInLineCount;
}
return myDest->sputc( ch );
}
// Special function...
int tabTo( int n )
{
int retval = 0;
while ( retval == 0 && myInLineCount < n ) {
if ( overflow( ' ' ) == EOF ) {
retval = EOF;
}
}
return retval;
}
};
Your manipulator would then be:
std::ostream&
operator<<( std::ostream& dest, SkipToChar const& manip )
{
TabbingOutputStreambuf* sb = dynamic_cast<TabbingOutputStreambuf*>( dest.rdbuf() );
assert( sb != nullptr );
try {
if ( sb->tabTo( manip.pos ) == EOF ) {
dest.setstate( std::badbit );
}
} catch ( ... ) {
dest.setstate( std::badbit );
}
return dest;
}
This is still not ideal, since it will fail with an unprotected
buffer, but you'd only use the manipulator in a context like:
void
generateOutput( std::ostream& dest )
{
TabbingOutputStreambuf tabber( dest );
dest << "Hello, " << SkipToChar( 7 ) << "world!";
// ...
}
And this will work regardless of the type of stream passed to
the function (including custom ostream classes that you don't
even know about).
EDIT:
One last point: don't bother with making things templates until you've got the basic version working. (For what it's worth, your code doesn't work correctly for wchar_t streams anyway. To output a space in them, you need to get the embedded locale, get the ctype facet from it, and use its widen member function.)

Cannot convert std::string to in initialization

I am having an odd problem:
metadata.h:
class metadata
{
public:
metadata ( std::string filename );
template <class T> T get ( std::string key ) { return m_data.get<T> ( key ); }
private:
boost::property_tree::ptree m_data;
};
metadata.cpp:
metadata::metadata ( std::string filename )
{
try {
boost::property_tree::read_info ( filename, m_data );
} catch ( boost::property_tree::file_parser_error err ) {
std::cerr << "[!] Unable to open "
<< filename
<< ": "
<< err.message()
<< "!"
<< std::endl;
throw except ( "Error opening metadata file." );
}
}
asset.h:
template <class T> class assetManager {
public:
void load ( std::string filename );
T get ( std::string filename );
T operator[] ( std::string filename );
void drop ( std::string filename ) { m_assets.erase ( filename ); }
void clear() { m_assets.clear(); }
private:
std::map<std::string,T> m_assets;
};
template <class T> void assetManager<T>::load ( std::string filename )
{
if ( m_assets [ filename ] == nullptr ) {
m_assets.erase ( filename );
m_assets.insert ( std::pair <std::string,T> ( filename, new T ( filename ) ) );
}
}
template <class T> T assetManager<T>::get ( std::string filename )
{
T ret = m_assets.at ( filename );
return ret;
}
For some reason, this line here:
m_metadata.load ( boost::filesystem::current_path().string() + "/engine.conf" );
I am getting the following compiler error from g++:
src/core/../core/../asset/asset.h|22|error: cannot convert ‘std::string {aka std::basic_string}’ to ‘metadata*’ in initialization
At no point, as far as I can tell, have I programmed anything even slightly resembling a conversion of a string into my metdata pointer here. Any ideas?
Inside assetManager<T>::load this subexpression
std::pair <std::string,T> ( filename, new T ( filename ) )
is obviously incorrect. new T will produce T *. Meanwhile your pair is declared with T as its second member. You cannot use T * to initialize T, unless you have a proper conversion constructor in T.
If T is metadata, then for this problem I'd actually expect an error message saying that it is impossible to convert metadata * to std::string, not the other way around. You will see the same error if you attempt this
metadata m(new metadata("test"));
Another issue is that you are creating a pair in which the first member has type std::string. However, in std::map<std::string, T>::value_type the first member of the pair is actually const std::string. The code will compile, but it will require a conversion from your std::pair<std::string, T> to map's std::pair<const std::string, T>. This might become performance issue. Which is why a much better idea would be to use std::map<std::string, T>::value_type as pair type, instead of trying to spell it out manually.
In the comments you stated that m_metadata is assetManager<metadata*>. In that case T is metadata *. That explains everything, including the error message. In that case the problem is even more simple and localized. This
new T ( filename )
alone is what causing the error. That means that new T produces a metadata * object and attempts to initialize it with std::string. Hence the error message. It is not possible to initialize metadata * with std::string because it is not possible to convert std::string to metadata *.
On top of that, such new expression will return a metadata ** value, which is definitely not what you need.
I changed m_metadata to an assetManager then made a few changes thus:
template <class T> class assetManager {
public:
void load ( std::string filename );
T get ( std::string filename );
T operator[] ( std::string filename );
void drop ( std::string filename ) { m_assets.erase ( filename ); }
void clear() { m_assets.clear(); }
private:
std::map<std::string,T*> m_assets;
};
template <class T> void assetManager<T>::load ( std::string filename )
{
if ( m_assets [ filename ] == nullptr ) {
m_assets.erase ( filename );
m_assets.insert ( std::pair <std::string,T*> ( filename, new T ( filename ) ) );
}
}
template <class T> T assetManager<T>::get ( std::string filename )
{
T ret = *m_assets.at ( filename );
return ret;
}
It compiles and runs now. Though my problem is fixed it is still a mystery to me why the compiler thinks I was trying a std::string to metadata* conversion.

C++ Map exc_bad_access (Apple only)

Code
Reads from
On Windows 7 and 8 it runs fine. However, when running in XCode 4 I get EXC_BAD_ACCESS on the second iteration when someone loads a map (select "Load Map" from title).
You can download the source with the XCode project
#include <string>
#include <map>
#include <iostream>
std::map <std::string, std::string> info;
std::string* get_key_val( std::string* line )
{
std::string key_val[2];
int start, end;
start = line->find_first_not_of( " " );
end = line->find_last_of( ":" );
if( start == -1 )
{
return NULL;
}
else if( end == -1 )
{
return NULL;
}
else
{
key_val[0] = line->substr( start, end - start );
}
start = line->find_first_not_of(" ", end + 1);
end = line->find_last_of( " \n\r" );
if( start == -1 )
{
return NULL;
}
else if( end == -1 )
{
return NULL;
}
else
{
key_val[1] = line->substr( start, end - start );
}
return key_val;
}
void parse_from_line( std::string* line )
{
std::string* keyv = get_key_val( line );
if( keyv[0].empty() == false && keyv[1].empty() == false ) info[ keyv[0] ] = keyv[1];
}
int main( int argc, char* args[] )
{
std::string line = "name: Foo";
parse_from_line( &line );
std::cout << "Hello " << info["name"].c_str();
}
Your get_key_val function starts like this:
std::string* Map::get_key_val( std::string* line )
{
std::string key_val[2];
It ends like this:
return key_val;
}
You're returning a pointer to a stack variable. The key_val variable ceases to exist upon return from the function, so you have an invalid pointer, and the two string values in the array get destroyed. Subsequent behavior is undefined.
With move semantics in C++11 onwards, its less necessary to do this. You can just return std::string and the move operator should avoid any wasteful copies.