class A
{
std::string val1;
A(std::string str) : val1(std::move(str)){}
};
class B: A
{
B(std::string str) : A(str){}
};
在這種情況下,str會被復制兩次,還是不會?在兒童課程中使用 Copy & Move 習語的最佳方式是什么?
uj5u.com熱心網友回復:
在這種情況下,最好的確定方法通常是記錄副本和移動。std::string 只需使用自定義復制和移動語意包裝到自定義類或結構中,如下所示:
class StringWrapper
{
public:
std::string data;
StringWrapper(const char* cstr)
: data(cstr) {}
// Copy constructor and assignment
StringWrapper(const StringWrapper& other)
: data(other.data)
{
std::cout << "Copy constructor!\n";
}
StringWrapper& operator=(const StringWrapper& other)
{
data = other.data;
std::cout << "Copy assignment!\n";
return *this;
}
// Move constructor and assignment
StringWrapper(StringWrapper&& other)
: data(std::move(other.data))
{
std::cout << "Move constructor!\n";
}
StringWrapper& operator=(StringWrapper&& other)
{
data = std::move(other.data);
std::cout << "Move assignment!\n";
return *this;
}
};
然后替換 by 的每次std::string使用StringWrapper:
class A
{
public: // Public for testing
StringWrapper val1;
A(StringWrapper str) : val1(std::move(str)){}
};
class B: public A // Private inheritance should be avoided
{
public: // Public for testing
B(StringWrapper str) : A(std::move(str)){}
};
通過一個小測驗:
int main()
{
StringWrapper strA("hello");
A a(strA);
std::cout << a.val1.data << '\n';
StringWrapper strB("world");
B b(strB);
std::cout << b.val1.data << '\n';
}
然后分析輸出:
Copy constructor!
Move constructor!
hello
Copy constructor!
Copy constructor!
Move constructor!
world
第一個副本發生在strA按值傳遞時。這是必要的,因為我們不希望更改strA影響a.val1.
第二個副本非常相似:它發生在strB按值傳遞時。出于同樣的原因,這也是必要的。
另一方面,第三個副本是多余的。它在傳遞str給 的建構式中的父建構式時發生B。str將在構建結束時被銷毀,所以我們最好移動它的內容而不是復制它:
class B: public A
{
public:
B(StringWrapper str) : A(std::move(str)){} // Replaced copy with move
};
固定的!
Copy constructor!
Move constructor!
hello
Copy constructor!
Move constructor!
Move constructor!
world
uj5u.com熱心網友回復:
如果您是 C 新手,最好簡單調查一下執行代碼時發生的情況,而不是做出錯誤的假設。
要查看發生了什么,只需替換std::string為您自己的類并在其中放入一些除錯輸出。
struct mystring
{
mystring() { std::cout << "Default" << std::endl; }
mystring( mystring&& ) { std::cout << "Move" << std::endl; }
mystring( const mystring& ) { std::cout << "Copy" << std::endl; }
mystring& operator=( const mystring& ) { std::cout << "Copy assign" << std::endl; return *this; }
mystring& operator=( mystring&& ) { std::cout << "Move assign" << std::endl; return *this; }
~mystring() { std::cout << "Delete" << std::endl; }
};
并帶有一些測驗代碼
int main()
{
std::cout << "1" << std::endl;
mystring ms;
std::cout << "2" << std::endl;
B b(std::move(ms));
std::cout << "3" << std::endl;
}
你會看見:
1
Default
2
Copy
Copy
Move
Delete
Delete
3
Delete
Delete
您的問題“在這種情況下, str 會被復制兩次,還是不會?” 答案是:是的,它復制了兩次!
如果您還希望轉發/移動按預期作業,則必須始終遵循三/五/零規則。
這將導致:
class A
{
private:
mystring val1;
public:
A(): val1{}{}
A( const mystring& str ): val1( str ) {}
A(mystring&& str) : val1(std::move(str)){}
// if you also want to assign a string later
A& operator=(const mystring& str ) { std::cout << "copy string to A" << std::endl; val1 = str; return *this; }
A& operator=(mystring&& str ) { std::cout << "move string to A" << std::endl; val1 = (std::move(str)); return *this; }
// and now all the stuff for copy/move of class itself:
A( const A& a): val1{ a.val1} {}
A( A&& a): val1{ std::move(a.val1)} {}
A& operator=( const A& a) { std::cout << "copy from A" << std::endl; val1=a.val1; return *this; }
A& operator=( A&& a) { std::cout << "move from A" << std::endl; val1=std::move(a.val1); return *this; }
};
class B: public A
{
public:
B(): A{}{}
B( const mystring& str ): A( str ) {}
B(mystring&& str) : A(std::move(str)){}
// and now all the stuff for copy/move of class itself:
B( const B& b): A{ b} {}
B( B&& b): A{ std::move(b)} {}
B& operator=( const B& b) { std::cout << "copy from B" << std::endl; A::operator=(b); return *this; }
B& operator=( B&& b) { std::cout << "move from B" << std::endl; A::operator=(std::move(b)); return *this; }
};
現在也測驗一下:
int main()
{
std::cout << "1" << std::endl;
mystring ms;
std::cout << "2" << std::endl;
B b(std::move(ms));
std::cout << "3" << std::endl;
//
std::cout << "4" << std::endl;
B b2;
// and now move assign
std::cout << "5" << std::endl;
b = std::move(b2);
std::cout << "6" << std::endl;
}
結果:
1
Default
2
Move
3
4
Default
5
move from B
move from A
Move assign
6
Delete
Delete
Delete
現在,第一步只有一個移動,移動分配也按預期作業。
看到它在這里運行
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/459985.html
