std::initializer_list를 사용한 초기화에는 복사가 포함됩니다.
12735 단어 cppoptimizationmemory
auto data = std::vector<std::string>{"example", "input", "data"};
주의할 점이 있습니다. 벡터 생성자의 인수는 먼저 생성된 다음 복사됩니다.
std::initializer_list
의 특성입니다. 매개변수가 일부 리소스 등을 처리하기 때문에 사소하게 복사할 수 없는 경우 문제가 될 수 있습니다. 짧은 문자열은 작은 문자열 최적화로 처리해야 하므로 문제가 되지 않지만 긴 문자열은 표준 라이브러리 구현에 따라 다릅니다. 작거나 그렇지 않은 경우)에는 세 가지 메모리 할당이 필요합니다. 하나는 문자열 생성 중, 두 번째는 벡터 항목용, 세 번째는 복사용입니다.auto data = std::vector<std::string>{
"long string that will likely be allocated on the heap"
}; // three memory allocations
메모리 할당 수를 추적하는 테스트 프로그램을 작성해 보겠습니다.
void* operator new (std::size_t count) {
std::cout << "new " << count << " bytes\n";
return std::malloc(count);
}
int main() {
std::cout << "Vector with small string:\n";
auto data = std::vector<std::string>{"small string"};
std::cout << "\nVector with long string:\n";
data = std::vector<std::string>{
"long string that will likely be allocated on the heap"
};
}
g++ test.cpp --std=c++17 -O2 -o test
에서 최적화된 g++ 9.4.0으로 컴파일했습니다. 프로그램 실행의 출력은 다음과 같습니다../test
Vector with small string:
new 32 bytes
Vector with long string:
new 56 bytes
new 32 bytes
new 56 bytes
여기서 우리는 작은 문자열
std::vector
에 대해 std::string
의 크기인 32바이트를 할당했음을 볼 수 있습니다. 긴 문자열을 처리하는 벡터를 생성하려면 3개의 메모리 할당이 필요합니다. 첫 번째는 매개변수 구성에서 가져오고 두 번째는 벡터 내부의 std::string
에 대한 메모리 할당이고 마지막은 매개변수의 복사본입니다.복사본을 제거하려면 피해야 합니다
std::initializer_list
. 대신 make_vector
함수를 작성해 봅시다. 내 초안은 다음과 같습니다.template <typename T, typename... U>
std::vector<std::decay_t<T>> make_vector(T&& arg, U&&... args) {
auto result = std::vector<std::decay_t<T>>{};
result.reserve(1 + sizeof...(args));
result.emplace_back(std::forward<T>(arg));
(result.emplace_back(std::forward<U>(args)), ...);
return result;
}
이제 매개변수를 구성하는
emplace_back
메서드로 전달되기 때문에 매개변수가 복사되지 않습니다. 중요한 것은 reserve
방법을 사용하여 한 번에 모든 매개변수에 대한 메모리를 할당하는 것입니다. 그렇지 않으면 복사 할당을 저장하지만 벡터 항목에 대한 중복 할당을 추가합니다.테스트 프로그램을 수정해 보겠습니다.
int main() {
std::cout << "String size: " << sizeof(std::string) << "\n";
std::cout << "\nVector with small string:\n";
auto data = std::vector<std::string>{"short vector"};
std::cout << "\nVector with a long string:\n";
data = std::vector<std::string>{
"a long string that will likely be allocated on the heap"};
using namespace std::literals;
std::cout << "\nmake_vector with a long string:\n";
data = make_vector(
"a long string that will likely be allocated on the heap"s);
std::cout << "\nVector with two long strings:\n";
data = std::vector<std::string>{
"a long string that will likely be allocated on the heap",
"another long string that will likely be allocated on the heap"};
std::cout << "\nmake_vector, two long strings:\n";
data = make_vector(
"a long string that will likely be allocated on the heap"s,
"another long string that will likely be allocated on the heap"s);
}
이제 출력이 더 좋아 보입니다. 설명을 위해 주석을 추가했습니다.
String size: 32
Vector with small string:
new 32 bytes # vector item (sizeof std::string)
Vector with a long string:
new 56 bytes # the argument
new 32 bytes # the vector item
new 56 bytes # argument copy
make_vector with a long string:
new 56 bytes # the string argument
new 32 bytes # the vector item
Vector with two long strings:
new 56 bytes # the first argument
new 62 bytes # the second argument
new 64 bytes # memory for two vector items
new 56 bytes # copy of the 1st argument
new 62 bytes # copy of the 2nd argument
make_vector, two long strings:
new 62 bytes # the second argument
new 56 bytes # the first argument
new 64 bytes # memory for two vector items
make_vector
를 사용하면 더 이상 문자열이 복사되지 않고 사용도 편리합니다.
Reference
이 문제에 관하여(std::initializer_list를 사용한 초기화에는 복사가 포함됩니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/maniowy/initializing-with-stdinitializerlist-involves-copying-2pe9텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)