2017-04-06 33 views
1

我对C++还很陌生,所以请耐心等待。String没有做什么? C++ 11

我想了解更多关于std :: move是如何工作的,我看到一个例子,他们使用std :: move将字符串移动到不同的函数,然后使用std :: cout显示没有字符串保留。我觉得很酷,让我们来看看,如果我可以让我自己的类,做同样的:

#include <iostream> 
#include <string> 

class integer 
{ 
private: 
    int *m_i; 
public: 
    integer(int i=0) : m_i(new int{i}) 
    { 
     std::cout << "Calling Constructor\n"; 
    } 

    ~integer() 
    { 
     if(m_i != nullptr) { 
      std::cout << "Deleting integer\n"; 
      delete m_i; 
      m_i = nullptr; 
     } 
    } 

    integer(integer&& i) : m_i(nullptr) // move constructor 
    { 
     std::cout << "Move Constructor\n"; 
     m_i = i.m_i; 
     i.m_i = nullptr; 
    } 
    integer(const integer& i) : m_i(new int) { // copy constructor 
     std::cout << "Copy Constructor\n"; 
     *m_i = *(i.m_i); 
    } 
//* 
    integer& operator=(integer&& i) { // move assignment 
     std::cout << "Move Assignment\n"; 
     if(&i != this) { 
      delete m_i; 
      m_i = i.m_i; 
      i.m_i = nullptr; 
     } 
     return *this; 
    } 
    integer& operator=(const integer &i) { // copy assignment 
     std::cout << "Copy Assignment\n"; 
     if(&i != this) { 
      m_i = new int; 
      *m_i = *(i.m_i); 
     } 
     return *this; 
    } 
    int& operator*() const { return *m_i; } 
    int* operator->() const { return m_i; } 

    bool empty() const noexcept { 
     if(m_i == nullptr) return true; 
     return false; 
    } 

    friend std::ostream& operator<<(std::ostream &out, const integer i) { 
     if(i.empty()) { 
      std::cout << "During overload, i is empty\n"; 
      return out; 
     } 
    out << *(i.m_i); 
    return out; 
    } 
}; 

void g(integer i) { std::cout << "G-wiz - "; std::cout << "The g value is " << i << '\n'; } 
void g(std::string s) { std::cout << "The g value is " << s << '\n'; } 

int main() 
{ 
    std::string s("Hello"); 

    std::cout << "Now for string\n"; 
    g(std::move(s)); 
    if(s.empty()) std::cout << "s is empty\n"; 
    g(s); 
    std::cout << "\nNow for integer\n"; 
    integer i = 77; 
    if(!i.empty()) std::cout << "i is " << i << '\n'; 
    else std::cout << "i is empty\n"; 
    g(i); 
    std::cout << "Move it\n"; 
    g(std::move(i)); // rvalue ref called 
    if(!i.empty()) std::cout << "i is " << i << '\n'; 
    else std::cout << "i is empty\n"; 
    g(i); 

    return 0; 
} 

这是我的输出:

Now for string 
The g value is Hello 
s is empty 
The g value is 

Now for integer 
Calling Constructor 
Copy Constructor 
i is 77 
Deleting integer 
Copy Constructor 
G-wiz - Copy Constructor 
The g value is 77 
Deleting integer 
Deleting integer 
Move it 
Move Constructor 
G-wiz - Copy Constructor 
The g value is 77 
Deleting integer 
Deleting integer 
i is empty 
Copy Constructor 

Process returned 255 (0xFF) execution time : 7.633 s 
Press any key to continue. 

正如你所看到的,当它进入克崩溃第二次,甚至从未获得运营商< <()的功能。它是如何空std ::字符串s可以传递给g我的空整数我崩溃程序?

编辑:修正新的int与新的int []错误。谢谢你。

+0

手动移动构造函数通常使用'std :: move'移动成员。 – Peter

+0

感谢您的帮助,解决了问题。如果我理解的是,在移动构造函数(和赋值运算符)中,我将i.m_i视为左值而不是右值。是对的吗? – davidbear

回答

1

您的“空整数”会因程序包含空指针而导致程序崩溃。当您在作业的右侧使用它时,您正试图对其进行解引用。

空字符串是一个正常的可用字符串。 std::string代码中没有未经检查的空指针取消引用。

你必须确保你的对象的空状态是一个可用的状态。从定义默认构造函数开始。这对你的班级有意义吗?如果不是,那么移动语义可能也不会。如果是,则移动构造函数中的移动对象应该最终处于与默认构造对象相同的状态。移动分配可以充当交换操作,所以右侧可能会空或不空。

如果你不想为你的类定义一个可用的空状态,并且仍然希望移动语义,那么你就不能在它被移动后使用一个对象。你仍然需要确保一个空物体是可破坏的。

+0

这个练习的要点不实用,但要学习std :: move如何工作。如何让一个空物体破坏? – davidbear

+1

析构函数不应该崩溃或有其他不良行为。它取决于析构函数的作用,但基本上如果有一个指针想要“删除”,指针必须指向一个可以被删除的对象,或者是一个“nullptr”。你们班上已经有这个了。注意另一个bug,有时候你会调用'new int',有时候会调用'new int [1]'。这是非法的。 –

+0

我修正了“new int/new int [1]”的问题(谢谢,见上)。我已经确定在调用std :: cout之前程序崩溃了,所以用空的整数调用g的行为与用空std :: string调用g不同。我仍然错过了一些东西。对不起,如此密集。 – davidbear

相关问题