std::copy to std::cout for std::pair
I've founded one new elegant way to solve this problem.
I've got many interest ideas when read answers:
- wrap iterator, for transform std::pair to std::string;
- wrap std::pair, for have a chance to overload operator<<(...);
- use usual std::for_each with printing functor;
- use std::for_each with boost::labda - looks nice, except accessing to std::pair< >::first and std::pair< >::second members;
I think I will use all of this ideas in future for solve different other problems.
But for this case I've understaded that I can formulate my bproblem as "transform map's data to strings and write them to output stream" instead "copy map's data to ouput stream". My solution looks like:
namespace
{
std::string toString( const std::pair< size_t, size_t >& data)
{
std::ostringstream str;
str << data.first << ", " << data.second;
return str.str();
}
} // namespace anonymous
std::transform(
some_map.begin(),
some_map.end(),
std::ostream_iterator< std::string >( std::cout, "\n" ),
toString );
I think this method is most short and expressive than others.
Does copy operator= exist for std::pair
std::pair
is copyable only as long as whatever's in a std::pair
is copyable. If you think about, for a few seconds, you will agree that this makes 100% sense.
std::pair<std::string, std::ifstream>
std::ifstream
is not copyable. You cannot copy std::ifstream
s. Putting it inside a std::pair
doesn't make it copyable.
But that's not the least of the problems in the shown code:
std::map<std::string, std::ifstream> files;
std::transform(mFileMap.begin(), mFileMap.end(), files.begin(),
// ...
The files
map is empty. files.begin()
will return the beginning iterator to an empty map, which will be the same value as files.end()
. Attempting to copy into an ending iterator (ignoring the fact that the underlying type is not copyable) will not end well.
Additionally, std::map
's key is constant, in the map, so that won't work either.
This is not how stuff gets added to a map, one needs to use a std::insert_iterator
.
So, to summarize, the following problems must be solved:
- This
std::pair
is not copyable. - A
std::insert_iterator
must be used to insert new key/value pairs into astd::map
.
Presuming you insist on your std::map
containing these values, you'll have to do some work to populate it, using std::map::emplace
, this will be the most practical way to drop new things into this map.
Returning an std::pairstd::shared_ptrA, std::unique_ptrB& from a function results in weirdness
std::pair<std::shared_ptr<A>, std::unique_ptr<B>&> FuncA() {
// ...
std::unique_ptr<B> b = std::make_unique<B>();
// ...
return {a,b};
}
A local std::unique_ptr<B>
is created and a reference to it is returned as the second element in the pair. This is a dangling reference and is later accessed, giving the program undefined behaviour.
Why is std::pair from anonymous object copying that object instead of moving?
There's a problem with how std::pair
is defined. I'd even say it's a minor defect in the standard.
It has two constructors that could be used here:
pair(const T1 &x, const T2 &y);
, whereT1
,T2
are template parameters of thepair
.template <class U1, class U2> pair(U1 &&x, U2 &&y);
If you do std::pair<A, A> a{A{}, A{}});
, then the second constructor is selected and all is well.
But if you do std::pair<A, A> a{{}, {}};
, the compiler can't use the second constructor because it can't deduce U1
, U2
, because {}
by itself has no type. So the first constructor is used and you get a copy.
For it to work properly, std::pair
should have an extra non-template constructor pair(T1 &&, T2 &&)
, and for a good measure two extra constructors: pair(const T1 &, T2 &&)
and pair(T1 &&, const T2 &)
.
Copy vs move in std::pair braced initialization
Let's take a look at two of the two-argument constructors of pair
: [pairs.pair]
EXPLICIT constexpr pair(const T1& x, const T2& y);
template<class U1, class U2> EXPLICIT constexpr pair(U1&& x, U2&& y);
The second constructor uses perfect forwarding, and U2
cannot be deduced from {}
. Therefore, the first version is selected when {}
is used. When Foo{}
is used instead, the argument has type Foo
, so U2
is deduced to be Foo
, causing the forwarding version to be selected.
How to update values in C++ std::pairint, int
Your first function has a bug. It reports when a robot is not found, but still dereferences the end iterator, which causes undefined behavior. Instead, you should return a pointer, which is conditionally null:
// Returns null if the robot is not found:
std::pair<int, int>*
World::getRobotLocation(char robot_name){
auto const location = robots.find(robot_name);
if (location == robots.end()) {
return nullptr;
}
return &location->second;
}
And in your other function, you check to see, if the pointer is not null, you update the value:
// Returns true if move happens,
// false otherwise.
bool
move(char robot, char direction) {
auto const robot_location = World::getRobotLocation(robot);
if (!robot_location) return false;
switch (direction) {
case 'L': {
++robot_location->first;
} break;
case 'D': {
--robot_location->second;
} break;
case 'R': {
--robot_location->first;
} break;
default: {
++robot_location->second;
} break;
}
return true;
}
Returning a pair of objects
For the second snippet,
auto f() {
std::vector<int> v0(100000);
std::vector<int> v1(100000);
return std::make_pair(std::move(v0),std::move(v1)); // is the move needed?
}
return
returns the result of the std::make_pair()
function. That's an RValue.
However, the OP's question probably condenses to whether (or why not) Named Return Value Optimization still applies to v0
/v1
when returned as a std::pair
.
Thereby, it's overlooked that v0
/v1
aren't subject of return
anymore, but become arguments of std::make_pair()
. As such, v0
/v1
are LValues – std::move(v0), std::move(v1)
have to be applied to turn them into RValues if move-semantic is intended.
Demo on coliru:
#include <iostream>
template <typename T>
struct Vector {
Vector(size_t n)
{
std::cout << "Vector::Vector(" << n << ")\n";
}
Vector(const Vector&)
{
std::cout << "Vector::Vector(const Vector&)\n";
}
Vector(const Vector&&)
{
std::cout << "Vector::Vector(const Vector&&)\n";
}
};
auto f1() {
Vector<int> v(100000);
return std::move(v); // over-pessimistic
}
auto f2() {
Vector<int> v(100000);
return v; // allows NRVO
}
auto f3() {
Vector<int> v0(100000);
Vector<int> v1(100000);
return std::make_pair(v0, v1); // copy constructor called for v0, v1
}
auto f4() {
Vector<int> v0(100000);
Vector<int> v1(100000);
return std::make_pair(std::move(v0),std::move(v1)); // move constructor called for v0, v1
}
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(f1());
DEBUG(f2());
DEBUG(f3());
DEBUG(f4());
}
Output:
f1();
Vector::Vector(100000)
Vector::Vector(const Vector&&)
f2();
Vector::Vector(100000)
f3();
Vector::Vector(100000)
Vector::Vector(100000)
Vector::Vector(const Vector&)
Vector::Vector(const Vector&)
f4();
Vector::Vector(100000)
Vector::Vector(100000)
Vector::Vector(const Vector&&)
Vector::Vector(const Vector&&)
Why doesn't RVO happen with structured bindings when returning a pair from a function using std::make_pair?
std::make_pair
is a function that takes the arguments by reference. Therefore temporaries are created from the two Test()
arguments and std::make_pair
constructs a std::pair
from these, which requires copy-constructing the pair elements from the arguments. (Move-constructing is impossible since your manual definition of the copy constructor inhibits the implicit move constructor.)
This has nothing to do with structured bindings or RVO or anything else besides std::make_pair
.
Because std::pair
is not an aggregate class, you cannot solve this by simply constructing the std::pair
directly from the two arguments either. In order to have a std::pair
construct the elements in-place from an argument list you need to use its std::piecewise_construct
overload:
auto func() {
return std::pair<Test, Test>(std::piecewise_construct, std::forward_as_tuple(), std::forward_as_tuple());
}
Related Topics
Is It True That There Is No Need to Learn C Because C++ Contains Everything
Linear Index Upper Triangular Matrix
How to Enable /Std:C++17 in VS2017 with Cmake
How Much Overhead Is There in Calling a Function in C++
Do Polymorphism or Conditionals Promote Better Design
What Does _T Stands for in a Cstring
Large 2D Array Gives Segmentation Fault
Templates: Template Function Not Playing Well with Class's Template Member Function
What Is a Good Easy to Use Profiler for C++ on Linux
Static_Assert on Initializer_List::Size()
C++ Objects: When Should I Use Pointer or Reference
How to Get Cmake to Recognize Pthread on Ubuntu
Why Do Linked Lists Use Pointers Instead of Storing Nodes Inside of Nodes
Why Do Functions/Objects Inside Anonymous Namespace Have External Linkage