What Is the Purpose of Std::Make_Pair VS the Constructor of Std::Pair

What is the purpose of std::make_pair vs the constructor of std::pair?

The difference is that with std::pair you need to specify the types of both elements, whereas std::make_pair will create a pair with the type of the elements that are passed to it, without you needing to tell it. That's what I could gather from various docs anyways.

See this example from http://www.cplusplus.com/reference/std/utility/make_pair/

pair <int,int> one;
pair <int,int> two;

one = make_pair (10,20);
two = make_pair (10.5,'A'); // ok: implicit conversion from pair<double,char>

Aside from the implicit conversion bonus of it, if you didn't use make_pair you'd have to do

one = pair<int,int>(10,20)

every time you assigned to one, which would be annoying over time...

Use of `std::make_pair` in std::pair : C++ STL

we can directly input values to a pair, and modify them as we like.
For example:

std::pair<int,int> newp;
std::cin>>newp.first>>newp.second;
newp.first = -1;

Some problems I can think of:

  1. You don't always have a stream object ready. std::cin is a very special case, and std::make_pair is a very generic function.

  2. Who says that both types in the pair support operator>>?

  3. Const correctness. You may want to have a const pair.

Let's put these three things together to create a non-compiling example:

#include <utility>
#include <iostream>

struct Foo
{
int i;
};

struct Bar
{
double d;
};

void printPair(std::pair<Foo, Bar> const& pair)
{
std::cout << pair.first.i << " " << pair.second.d << "\n";
}

void createAndPrintPairTwice(Foo const& foo, Bar const& bar)
{
// error 1: no std::cin, need to use foo and bar
// error 2: no operator>> for Foo or Bar
// error 3: cannot change pair values after initialisation
std::pair<Foo, Bar> const newp;
std::cin >> newp.first >> newp.second;
printPair(newp);
printPair(newp);
}

int main()
{
Foo foo;
foo.i = 1;
Bar bar;
bar.d = 1.5;
createAndPrintPairTwice(foo, bar);
}

std::make_pair solves all three problems and makes the code much nicer to read. Note that you don't have to repeat the pair's template arguments:

void createAndPrintPairTwice(Foo const& foo, Bar const& bar)
{
std::pair<Foo, Bar> const pair = std::make_pair(foo, bar);
printPair(pair);
printPair(pair);
}

What's true is that C++11 has rendered std::make_pair much less useful than before, because you can now also write:

void createAndPrintPairTwice(Foo const& foo, Bar const& bar)
{
auto const pair = std::pair<Foo, Bar> { foo, bar };
printPair(pair);
printPair(pair);
}

What's the different between make_pair and pair?

So on from this answer, std::ref does not work with test_vtor as follows:

std::vector<std::pair<Callback, int>> test_vtor; 

Even if you pass a reference:

test_vtor.push_back(std::make_pair(std::ref(test_map[1]), 1));

you cannot avoid your Callback being copied.
That's the same reason that declaring std::pair<Callback&, int> is not allowed.

Even if std::make_pair has this exceptional rule for std::reference_wrapper as follows:

... unless application of std::decay results in std::reference_wrapper<X> for some type X, in which case the deduced type is X&.

There will be always a new copy of Callback in test_vtor (whether it's moved or copied), which will surpass its reference-ness during the construction.

Multimap insert key typeinfo with std::make_pair vs std::pair constructor

The return type of the typeid is a std::type_info object, which has no constructors defined. As make_pair deduces the template arguments for its output pair from the parameters passed in, it deduces std::pair<std::type_info, int>. It then fails to create the required pair for the above reason.

Your other line creates the pair with explicit template parameters: std::pair<std::type_index, void *>. This time, you are creating an std::type_index object, which does have a constructor, which takes an std::type_info - exactly what you're giving it. So no problems.

Your make_pair line would compile if it was also given explicit template parameters:

mm.insert(std::make_pair<std::type_index, void *>(typeid(int), 0));

Why is it better to use std::make_* instead of the constructor?

Aside from the benefit of enabling argument deduction (as already mentioned in other answers), there are also some other benefits.

std::make_pair<T1, T2> takes care to not simply return std::pair<T1, T2>. If you pass in a value using std::ref, then the returned pair won't store a std::reference_wrapper, it will store a reference.

std::make_shared can combine allocations. shared_ptr needs some place to hold things like the refcount, weak pointer list, etc. that cannot be stored in the shared_ptr directly. These can be combined with the object being created, in one slightly larger block rather than in two separate blocks.

std::make_shared and std::make_unique both make sure that no object gets left behind if exceptions are thrown. If you call a function as f(std::shared_ptr<int>(new int), std::shared_ptr<int>(new int)), then it's possible the compiler first allocates two int objects, and then constructs two shared_ptr<int> objects. If the second allocation fails, and no shared_ptr<int> object is set up yet to release the memory on destruction, then you have a memory leak. std::make_shared and std::make_unique combine the allocation of int and the construction of std::shared_ptr<int> in a function call, and the other allocation of int and the other construction of std::shared_ptr<int> in another function call. Function calls cannot overlap, so if the second allocation fails, there is already a shared pointer that will be destroyed, undoing the first allocation as well.

Usefulness of std::make_pair and std::make_tuple in C++1z

In C++1z, is there a situation in which it is beneficial to use std::make_pair and std::make_tuple instead of using the constructors of std::pair and std::tuple?

There are always fun exceptions to every rule. What do you want to happen to std::reference_wrapper?

int i = 42;
auto r = std::ref(i);

pair p(i, r); // std::pair<int, std::reference_wrapper<int> >
auto q = std::make_pair(i,r); // std::pair<int, int&>

If you want the latter, std::make_pair is what you want.


Another situation cames in generic code. Let's say I have a template parameter pack that I want to turn into a tuple, would I write this?

template <typename... Ts>
auto foo(Ts... ts) {
return std::tuple(ts...);
}

Now the intent of that code is to probably to get a std::tuple<Ts...> out of it, but that's not necessarily what happens. It depends on Ts...:

  • if Ts... is a single object that is itself a tuple, you get a copy of it. That is, foo(std::tuple{1}) gives me a tuple<int> rather than a tuple<tuple<int>>.
  • if Ts... was a single object that is a pair, I get a tuple of those elements. That is, foo(std::pair{1, 2}) gives me a tuple<int, int> rather than a tuple<pair<int, int>>.

In generic code, I would stay away from using CTAD for types like tuple because it's never clear what you're going to get. make_tuple doesn't have this problem. make_tuple(tuple{1}) is a tuple<tuple<int>> and make_tuple(pair{1, 2}) is a tuple<pair<int, int>> because that's what you asked for.


Additionally, since std::make_pair is a function template, you can pass that into another function template that maybe wants to do something:

foo(std::make_pair<int, int>);

This doesn't seem super useful, but somebody somewhere is using it to solve a problem - and you can't just pass std::pair there.

Difference between make_pair and curly brackets { } for assigning a pair in C++?

I tried this in an online compiler, and as far as I can see the optimized assembly for make_pair is identical to {} syntax.

https://godbolt.org/z/P7Ugkt

Why does std::make_pair return a pair of reference types

As far as I know make_pair has the following prototype:

template<class Type1, class Type2>
std::pair<Type1,Type2> make_pair(Type1 first_value, Type2 second_value);

(Note: slightly different since C++11)

See also http://en.cppreference.com/w/cpp/utility/pair/make_pair.

This is also what the standard says in §20.3.3 [pairs.spec]. So this must be an error in the book (or you may have overlooked something).

Constructing std::pair of integers with a variable using post-increment

From cppreference:

When calling a function (whether or not the function is inline, and whether or not explicit function call syntax is used), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function.

So what is going on here is this.

int n = 0;
auto p = std::make_pair( n, n++ );

First we determine the overload of make_pair; we get:

make_pair<int&, int>( int&, int&& )

ie, the first argument is a rvalue reference (which ends up binding to n), the second in an lvalue reference (which ends up binding to the temporary that n++ returns).

We evaluate the arguments of make_pair. They are sequenced in an arbitrary manner, but you'll see it doesn't matter here.

Binding n to int& doesn't copy a value, it just stores a reference.

Binding n++ to int&& creates a temporary object, copies the value of n into it, then sets up a side effect to increase n afterwards.

When the side effect happens is the key here. As noted above, it has to happen sometime before the function make_pair is called.

It could happen before n is evaluated for the first argument, or after; it doesn't matter, because we are binding a reference to n to the argument. It is, however, evaluated before we do the body of make_pair.

So within make_pair, it is guaranteed to have a reference to n, whose value is 1, and a reference to a temporary whose value is 0. It then runs and returns a pair with those values.


It appears you misunderstood what n++ means -- it means "return the value of n, then afterwards increase it", it does not mean "return a value 1 bigger than n".

The way you return a value 1 bigger than n is n+1.

How does make_pair deduce the types implicitly?

It first creates a std::pair<double, char> thanks to type deduction of the helper function std::make_pair which creates a pair of exactly the same types than you passed to it, no matter to which type you later assign this pair to.

This object gets then assigned to a std::pair<int,int> which works thanks to a templated assignment operator. This operator basically allows assignable types (U1 to T1, U2 to T2) which internally assigns (in your case) a double to an int and a char to an int.

The language doesn't have a feature which "forecasts" the type of variable where the expression will be used, which would be required to make a pair<int,int> immediately without this step in between.

If you want to avoid that step you have to be explicit when constructing the pair, meaning that you shouldn't use the type deducting std::make_pair but rather std::pair's constructor which requires you to put the explicit types. However, I doubt this will increase performance thanks to optimization.



Related Topics



Leave a reply



Submit