I am doing a survey of how many special member functions get executed during the following member functions of vector
:
insert
emplace
push_back
emplace_back
under various run time conditions. My intent is to publish a paper that will compare these member functions with each other, and on each of the c++11 implementations of the std::lib: libstdc++, libc++, and vc++, and offer advice on when it is best to use each member function (when more than one choice is possible). I have data on libc++ and libstdc++-4.8, but I am lacking data on vc++.
I am looking for answers on vc++ which include the vc++ version number (2010, 2012, 2013). My intent is to give advice on the when each of these members should be preferred, and tempered by real-world experience. I will up-vote the first response for each vc++ version. My intent is not to bash any particular platform. However should my results encourage any existing platform to improve in the future, then that's gravy.
The test I would like to see the results of is:
#include <iostream>
#include <vector>
class X
{
int i_;
int* p_;
public:
struct special
{
unsigned c;
unsigned dt;
unsigned cc;
unsigned ca;
unsigned mc;
unsigned ma;
};
static special sp;
X(int i, int* p)
: i_(i)
, p_(p)
{
// std::cout << "X(int i, int* p)\n";
sp.c++;
}
~X()
{
// std::cout << "~X()\n";
sp.dt++;
}
X(const X& x)
: i_(x.i_)
, p_(x.p_)
{
// std::cout << "X(const X& x)\n";
sp.cc++;
}
X& operator=(const X& x)
{
i_ = x.i_;
p_ = x.p_;
// std::cout << "X& operator=(const X& x)\n";
sp.ca++;
return *this;
}
X(X&& x) noexcept
: i_(x.i_)
, p_(x.p_)
{
// std::cout << "X(X&& x)\n";
sp.mc++;
}
X& operator=(X&& x) noexcept
{
i_ = x.i_;
p_ = x.p_;
// std::cout << "X& operator=(X&& x)\n";
sp.ma++;
return *this;
}
};
std::ostream&
operator<<(std::ostream& os, X::special const& sp)
{
os << sp.c << '\n';
os << sp.dt << '\n';
os << sp.cc << '\n';
os << sp.ca << '\n';
os << sp.mc << '\n';
os << sp.ma << '\n';
return os;
}
X::special X::sp{};
int
main()
{
{
std::vector<X> v;
v.reserve(4);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--insert lvalue no reallocation--\n";
X::sp = {};
v.insert(v.begin(), x);
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(4);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--emplace lvalue no reallocation--\n";
X::sp = {};
v.emplace(v.begin(), x);
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(4);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--insert xvalue no reallocation--\n";
X::sp = {};
v.insert(v.begin(), std::move(x));
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(4);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--emplace xvalue no reallocation--\n";
X::sp = {};
v.emplace(v.begin(), std::move(x));
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(4);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
std::cout << "--insert rvalue no reallocation--\n";
X::sp = {};
v.insert(v.begin(), X{0,0});
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(4);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
std::cout << "--emplace rvalue no reallocation--\n";
X::sp = {};
v.emplace(v.begin(), X{0,0});
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(3);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--insert lvalue reallocation--\n";
X::sp = {};
v.insert(v.begin(), x);
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(3);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--emplace lvalue reallocation--\n";
X::sp = {};
v.emplace(v.begin(), x);
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(3);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--insert xvalue reallocation--\n";
X::sp = {};
v.insert(v.begin(), std::move(x));
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(3);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--emplace xvalue reallocation--\n";
X::sp = {};
v.emplace(v.begin(), std::move(x));
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(3);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
std::cout << "--insert rvalue reallocation--\n";
X::sp = {};
v.insert(v.begin(), X{0,0});
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(3);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
std::cout << "--emplace rvalue reallocation--\n";
X::sp = {};
v.emplace(v.begin(), X{0,0});
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(4);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--push_back lvalue no reallocation--\n";
X::sp = {};
v.push_back(x);
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(4);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--emplace_back lvalue no reallocation--\n";
X::sp = {};
v.emplace_back(x);
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(4);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--push_back xvalue no reallocation--\n";
X::sp = {};
v.push_back(std::move(x));
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(4);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--emplace_back xvalue no reallocation--\n";
X::sp = {};
v.emplace_back(std::move(x));
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(4);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
std::cout << "--push_back rvalue no reallocation--\n";
X::sp = {};
v.push_back(X{0,0});
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(4);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
std::cout << "--emplace_back rvalue no reallocation--\n";
X::sp = {};
v.emplace_back(X{0,0});
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(3);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--push_back lvalue reallocation--\n";
X::sp = {};
v.push_back(x);
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(3);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--emplace_back lvalue reallocation--\n";
X::sp = {};
v.emplace_back(x);
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(3);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--push_back xvalue reallocation--\n";
X::sp = {};
v.push_back(std::move(x));
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(3);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
X x{0,0};
std::cout << "--emplace_back xvalue reallocation--\n";
X::sp = {};
v.emplace_back(std::move(x));
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(3);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
std::cout << "--push_back rvalue reallocation--\n";
X::sp = {};
v.push_back(X{0,0});
std::cout << X::sp;
std::cout << "----\n";
}
{
std::vector<X> v;
v.reserve(3);
v.push_back(X(0,0));
v.push_back(X(0,0));
v.push_back(X(0,0));
std::cout << "--emplace_back rvalue reallocation--\n";
X::sp = {};
v.emplace_back(X{0,0});
std::cout << X::sp;
std::cout << "----\n";
}
}
For example, here is the output of this test on gcc-4.8: https://ideone.com/imAMnU
If someone discovers that the results are different on a gcc version after 4.8 and wants to offer those results, that would also be appreciated (and upvoted). In the event that I am unable to distinguish which equivalent responses came first, I am happy to upvote all of them. However at this time I am uncertain how I will choose a correct answer to this survey.
Contributors of data will surely be gratefully acknowledged in anything I might publish. I am also happy to post a link in this question to any conclusions that might be drawn from this data in the future.
In summary, I realize that this style of question is not the norm for SO. However it is asked in the spirit of furthering public knowledge in the C++ community, and with as much transparency as I can manage. If people want to close this question for whatever reasons, I accept that, but personally do not feel that is in the best interest of the C++ community.
Update
Here is the paper I spoke of that this survey made possible:
insert
vsemplace
VS2012 Code compiled with Release mode.
Command
cl /O2 /EHsc /W4 Console_12.cpp
Output
--insert lvalue no reallocation--
4
4
1
3
4
0
----
--emplace lvalue no reallocation--
8
15
2
3
10
6
----
--insert xvalue no reallocation--
12
26
2
3
17
12
----
--emplace xvalue no reallocation--
16
37
2
3
24
18
----
--insert rvalue no reallocation--
20
49
2
3
31
24
----
--emplace rvalue no reallocation--
24
60
2
3
38
30
----
--insert lvalue reallocation--
28
70
3
3
44
30
----
--emplace lvalue reallocation--
32
84
4
3
53
36
----
--insert xvalue reallocation--
36
98
4
3
63
42
----
--emplace xvalue reallocation--
40
112
4
3
73
48
----
--insert rvalue reallocation--
44
127
4
3
83
54
----
--emplace rvalue reallocation--
48
141
4
3
93
60
----
--push_back lvalue no reallocation--
52
148
5
3
96
60
----
--emplace_back lvalue no reallocation--
56
156
6
3
99
60
----
--push_back xvalue no reallocation--
60
164
6
3
103
60
----
--emplace_back xvalue no reallocation--
64
172
6
3
107
60
----
--push_back rvalue no reallocation--
68
181
6
3
111
60
----
--emplace_back rvalue no reallocation--
72
189
6
3
115
60
----
--push_back lvalue reallocation--
76
199
7
3
121
60
----
--emplace_back lvalue reallocation--
80
210
8
3
127
60
----
--push_back xvalue reallocation--
84
221
8
3
134
60
----
--emplace_back xvalue reallocation--
88
232
8
3
141
60
----
--push_back rvalue reallocation--
92
244
8
3
148
60
----
--emplace_back rvalue reallocation--
96
255
8
3
155
60
----
Added #define noexcept
which I believe will have been done in the VS2010 and 2012 cases as well.
Release results:
/GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd"Release\vc120.pdb" /fp:precise /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_LIB" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa"Release\" /EHsc /nologo /Fo"Release\" /Fp"Release\Howard.pch"
--insert lvalue no reallocation--
0
1
1
3
1
0
----
--emplace lvalue no reallocation--
0
3
1
0
3
6
----
--insert xvalue no reallocation--
0
3
0
0
4
6
----
--emplace xvalue no reallocation--
0
3
0
0
4
6
----
--insert rvalue no reallocation--
1
4
0
0
4
6
----
--emplace rvalue no reallocation--
1
4
0
0
4
6
----
--insert lvalue reallocation--
0
3
1
0
3
0
----
--emplace lvalue reallocation--
0
6
1
0
6
6
----
--insert xvalue reallocation--
0
6
0
0
7
6
----
--emplace xvalue reallocation--
0
6
0
0
7
6
----
--insert rvalue reallocation--
1
7
0
0
7
6
----
--emplace rvalue reallocation--
1
7
0
0
7
6
----
--push_back lvalue no reallocation
0
0
1
0
0
0
----
--emplace_back lvalue no reallocat
0
0
1
0
0
0
----
--push_back xvalue no reallocation
0
0
0
0
1
0
----
--emplace_back xvalue no reallocat
0
0
0
0
1
0
----
--push_back rvalue no reallocation
1
1
0
0
1
0
----
--emplace_back rvalue no reallocat
1
1
0
0
1
0
----
--push_back lvalue reallocation--
0
3
1
0
3
0
----
--emplace_back lvalue reallocation
0
3
1
0
3
0
----
--push_back xvalue reallocation--
0
3
0
0
4
0
----
--emplace_back xvalue reallocation
0
3
0
0
4
0
----
--push_back rvalue reallocation--
1
4
0
0
4
0
----
--emplace_back rvalue reallocation
1
4
0
0
4
0
----
Debug results:
/GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd"Debug\vc120.pdb" /fp:precise /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_LIB" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa"Debug\" /EHsc /nologo /Fo"Debug\"
--insert lvalue no reallocation--
0
1
1
3
1
0
----
--emplace lvalue no reallocation-
0
3
1
0
3
6
----
--insert xvalue no reallocation--
0
3
0
0
4
6
----
--emplace xvalue no reallocation-
0
3
0
0
4
6
----
--insert rvalue no reallocation--
1
4
0
0
4
6
----
--emplace rvalue no reallocation-
1
4
0
0
4
6
----
--insert lvalue reallocation--
0
3
1
0
3
0
----
--emplace lvalue reallocation--
0
6
1
0
6
6
----
--insert xvalue reallocation--
0
6
0
0
7
6
----
--emplace xvalue reallocation--
0
6
0
0
7
6
----
--insert rvalue reallocation--
1
7
0
0
7
6
----
--emplace rvalue reallocation--
1
7
0
0
7
6
----
--push_back lvalue no reallocatio
0
0
1
0
0
0
----
--emplace_back lvalue no realloca
0
0
1
0
0
0
----
--push_back xvalue no reallocatio
0
0
0
0
1
0
----
--emplace_back xvalue no realloca
0
0
0
0
1
0
----
--push_back rvalue no reallocatio
1
1
0
0
1
0
----
--emplace_back rvalue no realloca
1
1
0
0
1
0
----
--push_back lvalue reallocation--
0
3
1
0
3
0
----
--emplace_back lvalue reallocatio
0
3
1
0
3
0
----
--push_back xvalue reallocation--
0
3
0
0
4
0
----
--emplace_back xvalue reallocatio
0
3
0
0
4
0
----
--push_back rvalue reallocation--
1
4
0
0
4
0
----
--emplace_back rvalue reallocatio
1
4
0
0
4
0
----
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With