【问题标题】:What does String do that I'm not doing? c++11String 做了什么我没有做的事情? c++11
【发布时间】:2017-04-06 04:18:58
【问题描述】:

我还是 C++ 新手,所以请耐心等待。

我试图更多地了解 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.

如你所见,它在第二次进入 g 时崩溃,甚至没有进入 operator

编辑:修复了 new int 与 new int[] 错误。谢谢n.m。

【问题讨论】:

  • 手动移动构造函数通常使用std::move 来移动成员。
  • 感谢您的帮助,解决了问题。如果我理解是在移动构造函数(和赋值运算符)中,我将 i.m_i 视为左值而不是右值。对吗?

标签: c++11 stdstring


【解决方案1】:

您的“空整数”会使程序崩溃,因为它包含一个空指针。当您在作业的右侧使用它时,您正试图取消引用它。

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

您必须确保对象的空状态是可用的。首先定义一个默认构造函数。这对你的课有意义吗?如果不是,那么移动语义可能也不会。如果是,则移动构造函数中的已移动对象可能最终处于与默认构造对象相同的状态。移动赋值可以充当交换操作,因此右侧可能最终为空或不为空。

如果您不想为您的类定义一个可用的空状态,并且仍然需要移动语义,那么您根本无法在对象被移动后使用它。您仍然需要确保空对象是可破坏的。

【讨论】:

  • 这个练习的重点不是实际的,而是要了解 std::move 是如何工作的。如何使空对象可破坏?
  • 析构函数不应崩溃或有其他不良行为。这取决于析构函数的作用,但基本上如果有一个指向delete 的指针,该指针必须指向一个可以是deleted 或nullptr 的对象。你的课堂上已经有了。注意另一个错误,有时您调用new int,有时调用new int[1]。这是非法的。
  • 我修复了“new int/new int[1]”问题(谢谢,见上文)。我已经确定程序在调用 std::cout 之前崩溃了,因此使用空整数调用 g 的行为与使用空 std::string 调用 g 的行为在某种程度上有所不同。我仍然缺少一些东西。抱歉这么密集。
  • 我已经解释过了。你的空整数有一个空指针。您的访问函数在不检查的情况下取消引用指针。这在 C++ 中是不允许的。您需要确定一个空整数是否对您来说是一个有效的对象。目前尚不清楚空整数会有什么语义。一个空整数加2等于多少?打印一个空整数是什么意思?您需要仔细考虑,写下来并实施它。一个空字符串是有效的并且有明确的定义。
猜你喜欢
  • 2015-11-13
  • 2016-03-19
  • 1970-01-01
  • 2016-07-31
  • 2021-11-25
  • 2021-08-11
  • 2021-12-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多