为什么我的移动赋值运算符无法正常工作?看起来它也弄乱了 main 中的其余部分

问题描述 投票:0回答:2

主.cpp

int main()
{
    Mystring larry3 = "larry3"; //will call no-arg ctor not move ctor.
    Mystring larry4 = larry3; // deep copy ctor is being called correctly
    std::cout <<"before" << endl;
    larry4 = "larry4"; // move assignment operator is being called correctly
    larry4 = Mystring{"larry4Again"}; // move assignment should be called -- but things
                                      // seems to be messed after this line
    larry4.display(); // this is also not working
    std::cout <<"after" << endl; // this is also not working

    return 0;
}

我的字符串.cpp

//
// Created by kumarg on 17-11-2024.
//

#include "Mystring.h"
#include <iostream>
#include <cstring>

//no-arg ctror
Mystring::Mystring()
  :str{nullptr} {
  str = new char[1];
  *str = '\0'; //
  cout << "no-arg ctor" << endl;
}

//arg ctor
Mystring::Mystring(const char *s)
  :str{nullptr}{
  if(s == nullptr) { //if s points to nullptr then do same thing as no-arg ctor
    this->str = new char[1]; // this->str or str is same used in 3rd line from here
    *str = '\0';
  } else {
    str = new char[std::strlen(s) + 1];
    std::strcpy(this->str, s);
  }
  std::cout << "arg-ctor" <<endl;
}

//dtor
Mystring::~Mystring() {
  std::cout << "dtor called: " << str << endl;
  delete []str;
}

void Mystring::display() const {
  std::cout << this->str << endl;
}

//copy ctor - deep
Mystring::Mystring(const Mystring &source)
  :str{nullptr} {
  std::cout << "deep copy ctor" << endl;
  str = new char[std::strlen(source.str) +1];
  std::strcpy(this->str, source.str);
}

//move ctor
Mystring::Mystring(Mystring &&source)
  :str{source.str} {
  cout << "move ctor" << endl;
  source.str = nullptr;
}

//copy assignment operator implementation
Mystring &Mystring::operator=(const Mystring &rhs) {
  std::cout << "copy assignment operator" << endl;
  //check if both are same already
  if(this == &rhs)
    return *this;
  delete []str;
  str = new char[std::strlen(rhs.str) + 1];
  std::strcpy(this->str, rhs.str);
  return *this;
}

//move assignment operator
Mystring &Mystring::operator=(Mystring &&rhs) {
  std::cout << "move assignment operator" << endl;
  if(this == &rhs)
    return *this;
  delete []str;
  str = rhs.str;
  rhs.str = nullptr;
  return *this;
}

Mystring.h

//
// Created by kumarg on 16-11-2024.
//      

#ifndef MYSTRING_H
#define MYSTRING_H
#include <iostream>

using namespace std;

class Mystring {
private:
    char *str;
public:
    Mystring(); // default ctor
    Mystring(const char *source); //parameter ctor
    ~Mystring();
    Mystring(const Mystring &source); //copy ctor
    Mystring(Mystring &&source) noexcept; //move ctor

    void display() const;
    Mystring operator-(); // unary - operator overloading
    bool operator==(Mystring &rhs); // assignment operator overloading
    bool operator!=(Mystring &rhs); // !- operator overloading


    bool operator<(Mystring &lhs);
    bool operator>(Mystring &lhs);
    Mystring operator+(Mystring &lhs);
    //assignment (=) operator overloading, remember this called when we do s2 = s1(both are initilaized already)
    // = operator can be overloaded in 2 ways, copy and move, if l-value thenp copy will be called, if r-value move will be called
    Mystring &operator=(const Mystring &rhs);
    // = op overloading by move
    Mystring &operator=(Mystring &&rhs);
    //Mystring &operator+=(Mystring &lhs);    
};

#endif //MYSTRING_H

我的代码按照预期执行,直到 main 中的这一行:

larry4 = "larry4";

但是,在这行之后:

larry4 = Mystring{"larry4Again"};

我期待着 arg-ctor 调用,然后是 move 赋值调用。所以我期待来自 arg-ctor 的 cout,然后期待来自移动运算符赋值调用的 cout。最后我期待着来自 main 的 cout。

这一切都没有发生,我不明白为什么。

c++ c++11
2个回答
3
投票

问题与您的移动分配无关,而是在您的

Mystring
析构函数(
Mystring::~Mystring
)中,您在尝试在此行中打印它时不检查
str
是否为空:

std::cout << "dtor called: " << str << endl;

正如您在here所看到的,

operator<<
的重载
char*
不支持空指针:

如果

s
是空指针,则行为未定义。

您可以通过将打印语句更改为来修复它:

if (str) {
    std::cout << "dtor called: " << str << endl;
}
else {
    std::cout << "dtor called (null)" << endl;
}

现场演示


0
投票

问题出现在这一行之前:

larry4 = Mystring{"larry4Again"};

在析构函数中打印它之前检查

str
是否存在,或者不要尝试在 dtor 中打印它,因为你的移动赋值运算符使其成为 nullptr。

#include <iostream>
#include <cstring>

using namespace std;

class Mystring {
private:
public:
    char *str;
    Mystring(); // default ctor
    Mystring(const char *source); //parameter ctor
    ~Mystring();
    Mystring(const Mystring &source); //copy ctor
    Mystring(Mystring &&source); //move ctor

    void display() const;
    Mystring operator-(); // unary - operator overloading
    bool operator==(Mystring &rhs); // assignment operator overloading
    bool operator!=(Mystring &rhs); // !- operator overloading


    bool operator<(Mystring &lhs);
    bool operator>(Mystring &lhs);
    Mystring operator+(Mystring &lhs);
    //assignment (=) operator overloading, remember this called when we do s2 = s1(both are initilaized already)
    // = operator can be overloaded in 2 ways, copy and move, if l-value thenp copy will be called, if r-value move will be called
    Mystring &operator=(const Mystring &rhs);
    // = op overloading by move
    Mystring &operator=(Mystring &&rhs);
    //Mystring &operator+=(Mystring &lhs);   
};

//no-arg ctror
Mystring::Mystring()
  :str{nullptr} {
  str = new char[1];
  *str = '\0'; //
  cout << "no-arg ctor" << endl;
}

//arg ctor
Mystring::Mystring(const char *s)
  :str{nullptr}{
  if(s == nullptr) { //if s points to nullptr then do same thing as no-arg ctor
    this->str = new char[1]; // this->str or str is same used in 3rd line from here
    *str = '\0';
  } else {
    str = new char[std::strlen(s) + 1];
    std::strcpy(this->str, s);
  }
  std::cout << "arg-ctor" <<endl;
}

//dtor
Mystring::~Mystring() {
  std::cout << "dtor called: " << endl;
  delete []str;
}

void Mystring::display() const {
  std::cout << this->str << endl;
}

//copy ctor - deep
Mystring::Mystring(const Mystring &source)
  :str{nullptr} {
  std::cout << "deep copy ctor" << endl;
  str = new char[std::strlen(source.str) +1];
  std::strcpy(this->str, source.str);
}

//move ctor
Mystring::Mystring(Mystring &&source)
  :str{source.str} {
  cout << "move ctor" << endl;
  source.str = nullptr;
}

//copy assignment operator implementation
Mystring &Mystring::operator=(const Mystring &rhs) {
  std::cout << "copy assignment operator" << endl;
  //check if both are same already
  if(this == &rhs)
    return *this;
  delete []str;
  str = new char[std::strlen(rhs.str) + 1];
  std::strcpy(this->str, rhs.str);
  return *this;
}

//move assignment operator
Mystring &Mystring::operator=(Mystring &&rhs) {
  std::cout << "move assignment operator" ;
  if(this == &rhs){
  std::cout << " on same object" << endl;
  return *this;}
  delete []str;
  str = rhs.str;
  rhs.str = 0;
  std::cout << " with different objects => new str is " << str << endl;
  return *this;
}

int main()
{
    Mystring larry3 = "larry3"; //will call no-arg ctor not move ctor.
    Mystring larry4 = larry3; // deep copy ctor is being called correctly
    std::cout <<"before" << endl;
    std::cout <<"larry3 = "<< larry3.str <<"; larry4 = "<<larry4.str<< endl;
    larry4 = Mystring("larry4"); // move assignment operator is being called correctly
    std::cout <<"larry3 = "<< larry3.str <</*"; larry4 = "<<larry4.str<<*/ endl;
    larry4 = "larry5";
    
    std::cout <<"larry3 = "<< larry3.str <<"; larry4 = "<<larry4.str<< endl;
    larry4 = "larry4Again"; // move assignment should be called -- but things
                                      // seems to be messed after this line
                                      
    std::cout <<"larry3 = "<< larry3.str <<"; larry4 = "<<larry4.str<< endl;
    larry4.display(); // this is also not working
    std::cout <<"after" << endl; // this is also not working
    
    std::cout <<"larry3 = "<< larry3.str <<"; larry4 = "<<larry4.str<< endl;

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.