簡體   English   中英

std :: string移動構造函數實際上是移動的嗎?

[英]Does std::string move constructor actually move?

所以我在這里有一個小測試程序:

#include <string>
#include <iostream>
#include <memory>
#include <vector>

class Test
{
public:
  Test(const std::vector<int>& a_, const std::string& b_)
    : a(std::move(a_)),
      b(std::move(b_)),
      vBufAddr(reinterpret_cast<long long>(a.data())),
      sBufAddr(reinterpret_cast<long long>(b.data()))
  {}

  Test(Test&& mv)
    : a(std::move(mv.a)),
      b(std::move(mv.b)),
      vBufAddr(reinterpret_cast<long long>(a.data())),
      sBufAddr(reinterpret_cast<long long>(b.data()))
  {}

  bool operator==(const Test& cmp)
  {
    if (vBufAddr != cmp.vBufAddr) {
      std::cout << "Vector buffers differ: " << std::endl
        << "Ours: " << std::hex << vBufAddr << std::endl
        << "Theirs: " << cmp.vBufAddr << std::endl;
      return false;
    }

    if (sBufAddr != cmp.sBufAddr) {
      std::cout << "String buffers differ: " << std::endl
        << "Ours: " << std::hex << sBufAddr << std::endl
        << "Theirs: " << cmp.sBufAddr << std::endl;
      return false;
    }
  }

private:

  std::vector<int> a;
  std::string b;
  long long vBufAddr;
  long long sBufAddr;
};

int main()
{
  Test obj1 { {0x01, 0x02, 0x03, 0x04}, {0x01, 0x02, 0x03, 0x04}};
  Test obj2(std::move(obj1));

  obj1 == obj2;


  return 0;
}

我用於測試的軟件:

編譯器:gcc 7.3.0

編譯器標志:-std = c ++ 11

操作系統:Linux Mint 19(tara)上行版Ubuntu 18.04 LTS(仿生)

我在這里看到的結果是,移動后,矢量緩沖區仍然具有相同的地址,但字符串緩沖區不具有相同的地址。 因此,在我看來,它分配了新的,而不是僅僅交換緩沖區指針。 是什么導致這種行為?

您可能會看到小/短字符串優化的影響 為了避免對每個微小的字符串進行不必要的分配, std::string許多實現包含一個小的固定大小的數組來保存小字符串而不需要new (這個數組通常會重新利用動態分配時不需要的其他一些成員沒有被使用,所以它消耗很少或沒有額外的內存來提供它,無論是小string還是大string s),並且這些字符串不會受益於std::move (但它們很小,所以沒關系)。 較大的字符串將需要動態分配,並將按預期傳輸指針。

僅供演示,這個代碼在g++

void move_test(std::string&& s) {
    std::string s2 = std::move(s);
    std::cout << "; After move: " << std::hex << reinterpret_cast<uintptr_t>(s2.data()) << std::endl;
}

int main()
{
    std::string sbase;

    for (size_t len=0; len < 32; ++len) {
        std::string s1 = sbase;
        std::cout << "Length " << len << " - Before move: " << std::hex << reinterpret_cast<uintptr_t>(s1.data());
        move_test(std::move(s1));
        sbase += 'a';
    }
}

在線嘗試!

產生高(堆棧)地址,在移動結構上改變長度為15或更小(可能隨架構指針大小而變化),但切換到低(堆)地址,一旦你達到16或更高的長度(移動開關),移動構造后保持不變是16,而不是17,因為它是NUL終止字符串,因為C ++ 11和更高版本需要它)。

要100%明確:這是一個實現細節。 C ++規范的任何部分都不需要這種行為,所以你不應該完全依賴它,當它發生時,你不應該依賴於特定字符串長度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM