벡터의 C ++ 11 emplace_back?
다음 프로그램을 고려하십시오.
#include <string>
#include <vector>
using namespace std;
struct T
{
int a;
double b;
string c;
};
vector<T> V;
int main()
{
V.emplace_back(42, 3.14, "foo");
}
작동하지 않습니다.
$ g++ -std=gnu++11 ./test.cpp
In file included from /usr/include/c++/4.7/x86_64-linux-gnu/bits/c++allocator.h:34:0,
from /usr/include/c++/4.7/bits/allocator.h:48,
from /usr/include/c++/4.7/string:43,
from ./test.cpp:1:
/usr/include/c++/4.7/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = T; _Args = {int, double, const char (&)[4]}; _Tp = T]’:
/usr/include/c++/4.7/bits/alloc_traits.h:253:4: required from ‘static typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = T; _Args = {int, double, const char (&)[4]}; _Alloc = std::allocator<T>; typename std::enable_if<std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::value, void>::type = void]’
/usr/include/c++/4.7/bits/alloc_traits.h:390:4: required from ‘static void std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = T; _Args = {int, double, const char (&)[4]}; _Alloc = std::allocator<T>]’
/usr/include/c++/4.7/bits/vector.tcc:97:6: required from ‘void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {int, double, const char (&)[4]}; _Tp = T; _Alloc = std::allocator<T>]’
./test.cpp:17:32: required from here
/usr/include/c++/4.7/ext/new_allocator.h:110:4: error: no matching function for call to ‘T::T(int, double, const char [4])’
/usr/include/c++/4.7/ext/new_allocator.h:110:4: note: candidates are:
./test.cpp:6:8: note: T::T()
./test.cpp:6:8: note: candidate expects 0 arguments, 3 provided
./test.cpp:6:8: note: T::T(const T&)
./test.cpp:6:8: note: candidate expects 1 argument, 3 provided
./test.cpp:6:8: note: T::T(T&&)
./test.cpp:6:8: note: candidate expects 1 argument, 3 provided
이를 수행하는 올바른 방법은 무엇이며 그 이유는 무엇입니까?
(또한 단일 및 이중 중괄호 시도)
{}
구문을 사용하여 새 요소를 초기화 할 수 있습니다 .
V.emplace_back(T{42, 3.14, "foo"});
이것은 최적화되거나 최적화되지 않을 수 있지만 그래야합니다.
이 작업을 수행하려면 생성자를 정의해야합니다. 코드로는 수행 할 수도 없습니다.
T a(42, 3.14, "foo");
그러나 이것은 당신이 emplace 일을하기 위해 필요한 것입니다.
그래서 그냥:
struct T {
...
T(int a_, double b_, string c_) a(a_), b(b_), c(c_) {}
}
원하는 방식으로 작동합니다.
클래스에 대한 ctor를 명시 적으로 정의해야합니다.
#include <string>
#include <vector>
using namespace std;
struct T
{
int a;
double b;
string c;
T(int a, double b, string &&c)
: a(a)
, b(b)
, c(std::move(c))
{}
};
vector<T> V;
int main()
{
V.emplace_back(42, 3.14, "foo");
}
The point of using emplace_back
is to avoid creating a temporary object, which is then copied (or moved) to the destination. While it is also possible to create a temporary object, then pass that to emplace_back
, it defeats (at least most of) the purpose. What you want to do is pass individual arguments, then let emplace_back
invoke the ctor with those arguments to create the object in place.
Of course, this is not an answer, but it shows an interesting feature of tuples:
#include <string>
#include <tuple>
#include <vector>
using namespace std;
using T = tuple <
int,
double,
string
>;
vector<T> V;
int main()
{
V.emplace_back(42, 3.14, "foo");
}
If you do not want to (or cannot) add a constructor, specialize allocator for T (or create your own allocator).
namespace std {
template<>
struct allocator<T> {
typedef T value_type;
value_type* allocate(size_t n) { return static_cast<value_type*>(::operator new(sizeof(value_type) * n)); }
void deallocate(value_type* p, size_t n) { return ::operator delete(static_cast<void*>(p)); }
template<class U, class... Args>
void construct(U* p, Args&&... args) { ::new(static_cast<void*>(p)) U{ std::forward<Args>(args)... }; }
};
}
Note: Member function construct shown above cannot compile with clang 3.1(Sorry, I don't know why). Try next one if you will use clang 3.1 (or other reasons).
void construct(T* p, int a, double b, const string& c) { ::new(static_cast<void*>(p)) T{ a, b, c }; }
This seems to be covered in 23.2.1/13.
First, definitions:
Given a container type X having an allocator_type identical to A and a value_type identical to T and given an lvalue m of type A, a pointer p of type T*, an expression v of type T, and an rvalue rv of type T, the following terms are defined.
Now, what makes it emplace-constructible:
T is EmplaceConstructible into X from args , for zero or more arguments args, means that the following expression is well-formed: allocator_traits::construct(m, p, args);
And finally a note about the default implementation of the construct call:
Note: A container calls allocator_traits::construct(m, p, args) to construct an element at p using args. The default construct in std::allocator will call ::new((void*)p) T(args), but specialized allocators may choose a different definition.
This pretty much tells us that for a default (and potentially the only) allocator scheme you must have defined a constructor with the proper number of arguments for the thing you're trying to emplace-construct into a container.
you have to define a constructor for your type T
because it contains an std::string
which is not trivial.
moreover, it would be better to define (possible defaulted) move ctor/assign (because you have a movable std::string
as member) -- this would help to move your T
much more efficient...
or, just use T{...}
to call overloaded emplace_back()
as recommended in neighboug response... everything depends on your typical use cases...
참고URL : https://stackoverflow.com/questions/13812703/c11-emplace-back-on-vectorstruct
'developer tip' 카테고리의 다른 글
npm / yeoman 설치-sudo없이 각진 생성기 (0) | 2020.10.28 |
---|---|
Python : 런타임에 메서드 및 속성 변경 (0) | 2020.10.28 |
MySQL-피연산자는 1 개의 열을 포함해야합니다. (0) | 2020.10.27 |
Angular에서 $ location.path를 $ http.post 성공 콜백으로 리디렉션하는 방법 (0) | 2020.10.27 |
: after 요소가 다음 줄로 줄 바꿈되지 않도록 방지 (0) | 2020.10.27 |