日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

std:move基本用法和理解

發布時間:2025/3/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 std:move基本用法和理解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

場景:

  • C++ 標準庫使用比如vector::push_back 等這類函數時,會對參數的對象進行復制,連數據也會復制.這就會造成對象內存的額外創建, 本來原意是想把參數push_back進去就行了.
  • C++11 提供了std::move 函數來把左值轉換為xrvalue, 而且新版的push_back也支持&&參數的重載版本,這時候就可以高效率的使用內存了.
  • 對指針類型的標準庫對象并不需要這么做.
  • 參考:

    1. Move Constructors and Move Assignment Operators (C++)
    2. std::move

    說明:

  • std::move(t) 用來表明對象t 是可以moved from的,它允許高效的從t資源轉換到lvalue上.
  • 注意,標準庫對象支持moved from的左值在moved 之后它的對象原值是有效的(可以正常析構),但是是unspecified的,可以理解為空數據,但是這個對象的其他方法返回值不一定是0,比如size().所以,moved from 之后的對象最好還是不要使用吧?(如有不正確理解,請告知)
  • 對本身進行move,并賦值給本身是undefined的行為.
  • std::vector<int> v = {2, 3, 3}; v = std::move(v); // undefined behavior

    std::move 的函數原型.

    /*** @brief Convert a value to an rvalue.* @param __t A thing of arbitrary type.* @return The parameter cast to an rvalue-reference to allow moving it. */ template<typename _Tp>constexpr typename std::remove_reference<_Tp>::type&&move(_Tp&& __t) noexcept{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }

    結構體 remove_reference 的原型,就是重載了多個結構體模板來獲取原類型 type.

    /// remove_reference template<typename _Tp>struct remove_reference{ typedef _Tp type; };template<typename _Tp>struct remove_reference<_Tp&>{ typedef _Tp type; };template<typename _Tp>struct remove_reference<_Tp&&>{ typedef _Tp type; };

    例子

    以下用兩個例子來說明std::move的用法.

    例子1

    – 原lvalue值被moved from之后值被轉移,所以為空字符串.
    – 摘錄自cppreference

    void TestSTLObject() {std::string str = "Hello";std::vector<std::string> v;// uses the push_back(const T&) overload, which means// we'll incur the cost of copying strv.push_back(str);std::cout << "After copy, str is \"" << str << "\"\n";// uses the rvalue reference push_back(T&&) overload,// which means no strings will be copied; instead, the contents// of str will be moved into the vector. This is less// expensive, but also means str might now be empty.v.push_back(std::move(str));std::cout << "After move, str is \"" << str << "\"\n";std::cout << "The contents of the vector are \"" << v[0]<< "\", \"" << v[1] << "\"\n";}

    輸出:

    After copy, str is "Hello" After move, str is "" The contents of the vector are "Hello", "Hello"

    例子2

    – 自定義自己的類對象支持moved from 操作,需要實現 Move Constructors and Move Assignment Operators

    #include <iostream> #include <stdio.h>#include <utility> #include <vector> #include <string>class MemoryBlock { public:// Simple constructor that initializes the resource.explicit MemoryBlock(size_t length): _length(length), _data(new int[length]){std::cout << "In MemoryBlock(size_t). length = "<< _length << "." << std::endl;}// Destructor.~MemoryBlock(){std::cout << "In ~MemoryBlock(). length = "<< _length << ".";if (_data != nullptr){std::cout << " Deleting resource.";// Delete the resource.delete[] _data;}std::cout << std::endl;}// Copy constructor.MemoryBlock(const MemoryBlock& other): _length(other._length), _data(new int[other._length]){std::cout << "In MemoryBlock(const MemoryBlock&). length = "<< other._length << ". Copying resource." << std::endl;std::copy(other._data, other._data + _length, _data);}// Copy assignment operator.MemoryBlock& operator=(const MemoryBlock& other){std::cout << "In operator=(const MemoryBlock&). length = "<< other._length << ". Copying resource." << std::endl;if (this != &other){// Free the existing resource.delete[] _data;_length = other._length;_data = new int[_length];std::copy(other._data, other._data + _length, _data);}return *this;}// Retrieves the length of the data resource.size_t Length() const{return _length;}// Move constructor.MemoryBlock(MemoryBlock&& other): _data(nullptr), _length(0){std::cout << "In MemoryBlock(MemoryBlock&&). length = "<< other._length << ". Moving resource." << std::endl;// Copy the data pointer and its length from the// source object._data = other._data;_length = other._length;// Release the data pointer from the source object so that// the destructor does not free the memory multiple times.other._data = nullptr;other._length = 0;}// Move assignment operator.MemoryBlock& operator=(MemoryBlock&& other){std::cout << "In operator=(MemoryBlock&&). length = "<< other._length << "." << std::endl;if (this != &other){// Free the existing resource.delete[] _data;// Copy the data pointer and its length from the// source object._data = other._data;_length = other._length;// Release the data pointer from the source object so that// the destructor does not free the memory multiple times.other._data = nullptr;other._length = 0;}return *this;}private:size_t _length; // The length of the resource.int* _data; // The resource. };void TestSTLObject() {std::string str = "Hello";std::vector<std::string> v;// uses the push_back(const T&) overload, which means// we'll incur the cost of copying strv.push_back(str);std::cout << "After copy, str is \"" << str << "\"\n";// uses the rvalue reference push_back(T&&) overload,// which means no strings will be copied; instead, the contents// of str will be moved into the vector. This is less// expensive, but also means str might now be empty.v.push_back(std::move(str));std::cout << "After move, str is \"" << str << "\"\n";std::cout << "The contents of the vector are \"" << v[0]<< "\", \"" << v[1] << "\"\n";}void TestMyObjectWithoutUseMove() {std::vector<MemoryBlock> v;MemoryBlock mb1(25);// MemoryBlock mb2(75);// MemoryBlock mb3(50);v.push_back(mb1);//v.push_back(mb2);//v.insert(v.begin() + 1, mb3); }void TestMyObjectWithUseMove() {std::vector<MemoryBlock> v;MemoryBlock mb1(25);// MemoryBlock mb2(75);// MemoryBlock mb3(50);v.push_back(std::move(mb1));//v.push_back(MemoryBlock(75));//v.insert(v.begin() + 1, MemoryBlock(50)); }int main(int argc, char const *argv[]) {//TestSTLObject();TestMyObjectWithoutUseMove();std::cout << "......................................." << std::endl;TestMyObjectWithUseMove();return 0; }

    輸出:
    1. 注意,第一個函數每個對象多調用了拷貝構造函數,多創建了一次,而使用了move操作的只是移動了資源
    2. 注意,vector即使 push_back 第二個對象時,會移動第一個對象,很奇怪,如果你把注釋去掉的話,會發現資源 Moving 很多次,這是 vector 實現影響了,比較清楚的看出來 Move 的特性的就是 push_back 一個參數.
    3. 注意,g++ 4.8.1 的 vector push_back 多個對象時優化的沒 vs 好,vs 是調用 Move 構造器,而 g++ 是調用 Copy 構造器,你會發現拷貝構造函數會調用很多次.

    In MemoryBlock(size_t). length = 25. In MemoryBlock(const MemoryBlock&). length = 25. Copying resource. In ~MemoryBlock(). length = 25. Deleting resource. In ~MemoryBlock(). length = 25. Deleting resource. ....................................... In MemoryBlock(size_t). length = 25. In MemoryBlock(MemoryBlock&&). length = 25. Moving resource. In ~MemoryBlock(). length = 0. In ~MemoryBlock(). length = 25. Deleting resource.

    總結

    以上是生活随笔為你收集整理的std:move基本用法和理解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。