c++ vector에서 reallocation이 일어날 때 값들이 복사되나요? 이동하나요?

dnfwlq8054의 이미지

만약 v라는 백터가 있다고 가정해보겠습니다.

v[5] = { 1, 2, 3, 4, 5};

// v.capacity() = 5

여기서 push_back(100)이 일어났을 때,

capacity() 값을 초과되서 reallocation이 일어나는걸 알고 있습니다.

여기서 궁금한점은 C++ 11 이상 버전에서 move라는 키워드를 만들어서 사용하고 있는걸로 알고 있는데,

백터에서 reallocation이 일어나면 복사하는게 아니라 move 시키나요?

자료를 찾아본 결과 백터의 복사생성자 및 소멸자 때문에 오버헤드가 많아져서 이를 해결하고자 나온게

move개념으로 알고 있는데, 그래서 백터의 함수를 보면 emplace나 emplace_back()이 있는걸 알 수 있습니다.

같은말 하는 것 같아서 죄송하지만 자료를 찾아봐도 잘 나오질 않아서 질문 올립니다.

백터가 reallocation 되면 기존꺼를 새로운 영역에 복사한 후 기존 백터를 파괴시키는지

아니면 기존꺼를 새로운 영역에 이동시킨 후 기존 백터를 파괴시키는지...

궁금합니다.!!

qmir의 이미지

기존꺼를 새로운 영역에 이동시킨 후 기존 백터를 파괴시킵니다

익명 사용자의 이미지

직접 테스트해보세요:

#include <iostream>
#include <vector>
using namespace std;
 
class base{
public:
    base() = default;
    ~base() = default;
    base(const base &b) noexcept { cout << b.name() << " is copied!"; }
    base(base &&b) noexcept { cout << b.name() << " is moved!"; }
 
    virtual const char *name() const noexcept { return "base"; }
};
 
class movable: public base{
public:
    movable() = default;
    ~movable() = default;
    movable(const movable &b) = default;
    movable(movable &&b) = default;
 
    virtual const char *name() const noexcept override { return "movable"; }
};
 
class noncopyable: public base{
public:
    noncopyable() = default;
    ~noncopyable() = default;
    noncopyable(const noncopyable &b) = delete;
    noncopyable(noncopyable &&b) = default;
 
    virtual const char *name() const noexcept override { return "noncopyable"; }
};
 
class nonmovable1: public base{
public:
    nonmovable1() = default;
    ~nonmovable1() = default;
    nonmovable1(const nonmovable1 &b) = default;
    nonmovable1(nonmovable1 &&b) = delete;
 
    virtual const char *name() const noexcept override { return "nonmovable1"; }
};
 
class nonmovable2: public base{
public:
    nonmovable2() = default;
    ~nonmovable2() = default;
    nonmovable2(const nonmovable2 &b) = default;
    nonmovable2(nonmovable2 &&b) noexcept(false) { /* Do nothing */ }
 
    virtual const char *name() const noexcept override { return "nonmovable2"; }
};
 
template <typename T>
static void move_test(){
    vector<T> v;
    v.emplace_back();
    v.shrink_to_fit();
    cout << "Test for " << T().name() << ":\n> ";
    v.emplace_back();
    cout << '\n';
}
 
int main(){
    move_test<movable>();
    move_test<noncopyable>();
    move_test<nonmovable1>();
    move_test<nonmovable2>();
    return 0;
}

적당히 c++17을 지원하는 컴파일러로 적당히 빌드해서 실행하시면 됩니다.

저는 우분투에서 g++ 9.2로 아래와 같이 빌드했습니다:

g++-9.2 -std=c++17 -pedantic -pedantic-errors -O3 -o move_test move_test.cpp

jick의 이미지

찾아보니까 좀 복잡한데,

1. 만약 move constructor가 있고 noexcept이면 이를 이용합니다.
2. 만약 move constructor와 copy constructor가 둘 다 있는데 move가 noexcept가 아니면, copy를 이용합니다.
3. 하지만 move constructor밖에 없고 copy가 존재하지 않는다면 어쩔 수 없이 move를 이용합니다.

이런 복잡한 룰이 존재하는 이유는 "vector를 resize하는 도중에 예외가 발생하면 resize는 취소되고 벡터는 resize 하기 이전과 논리적으로 같은 상태를 유지해야 한다"라는 요구사항을 만족시키기 위해서...라고 합니다. (다만 위의 3의 경우에 move 도중 예외가 발생하면 이 요구조건은 만족시킬 수 없습니다.)

참조: https://stackoverflow.com/questions/8001823/how-to-enforce-move-semantics-when-a-vector-grows
https://en.cppreference.com/w/cpp/utility/move_if_noexcept

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.