0

//头文件中:类定义:

class myString
{
public:

        myString(void);
        myString(const char *str);

        myString(const myString &); //copy constructor 
        ~myString(void); //destructor

        void swap(myString &from);


private:

        char *stringPtr;
        int stringLen;
};

//在cpp文件中,定义它们的成员函数

myString::myString(const char *str)
{
    stringLen = strlen(str);

    stringPtr = new char[stringLen+1];

    strcpy(stringPtr,str);
    cout << "constructor with parameter called"<<endl;
}

myString::myString(const myString &str)
{

    stringPtr = new char[str.stringLen +1];
    strcpy(stringPtr,str.stringPtr);
    cout << "copyconstructor"<<endl;
}


void myString::swap(myString &from)
{
    myString buffer(from);
    int lengthBuffer = from.stringLen;

    from = new char[stringLen+1];
    from.stringLen = stringLen;
    strcpy(from.stringPtr, stringPtr);


    stringPtr = new char[lengthBuffer+1];
    stringLen = lengthBuffer;
    strcpy(stringPtr,buffer.stringPtr);
}
4

4 回答 4

2

您不能修改参考。即使你用指针替换它,修改指针也不会修改指向的对象。相反,您需要处理参考 - 只需交换字段。

void myString::swap(myString &from)
{
    std::swap( stringLen, from.stringLen );
    std::swap( stringPtr, from.stringPtr );
}

以上是用户 sbi在评论中建议的使用 std::swap() 。这完全等同于以下内容(仅用于说明,不要重新发明 STL):

void myString::swap(myString &from)
    // First remember own length and pointer
    const int myOldLen = stringLen;
    char* myOldPtr = stringPtr;
    // now copy the length and pointer from that other string
    stringLen = from.stringLen;
    stringPtr = from.stringPtr;
    // copy remembered length and pointer to that other string
    from.StringLen = myOldLen;
    from.StringPtr = myOldPtr;
    // done swapping
}

即使调用自交换,两者都可以工作:

myString string;
string.swap( string );
于 2009-10-22T06:17:26.550 回答
1

myString::swap()关于函数中的错误,您已经得到了一些很好的答案。但是,我想再添加一个。该功能有很多问题,我首先发现很难想到从哪里开始。但后来我意识到你在一些我想指出的基本问题上失败了:

作为惯例,一个被调用的函数swap应该执行它的任务

  1. 在 O(1)
  2. 没有抛出异常。

(是的,我知道,有例外:std::tr1::array<>::swap()。但这些应该是非常合理的。)您的实施在两个帐户上都失败了。它是 O(n) ( strcpy) 并且可能会抛出异常 ( new) ——而且这样做是不必要且没有正当理由的。

当您查看 时myString,您会发现它只有两条成员数据,它们都是内置类型。这意味着交换这个类的两个对象非常简单,同时保持上面提到的约定:只需交换成员数据。这就像调用std::swap它们一样简单:

void myString::swap(myString &from)
{
  std::swap(this->stringPtr,from.stringPtr);
  std::swap(this->stringLen,from.stringLen);
}

这是永远不会失败的(交换两个指针和两个整数不会失败),在 O(1) 中执行,非常容易理解(好吧,无论如何,一旦你掌握了交换;它是实现特定于类的swap函数),并且由两行代码组成,调用在标准库中经过良好测试的东西,而不是 8 行代码执行容易出错(在您的情况下是错误的)手动内存管理。

注意 1:完成此操作后,您应该专门std::swap为您的课程调用您的实现:

namespace std { // only allowed for specializing function templates in the std lib
  template<>
  inline void std::swap<myString>(myString& lhs, myString& rhs)
  {
    lhs.swap(rhs);
  }

注意 2:为您的班级实施分配的最佳(简单、异常安全和自分配安全)方法是使用它的swap

myString& myString::operator=(const myString& rhs)
{
   myString tmp(rhs); // invoke copy ctor
   this->swap(tmp); // steal data from temp and leave it with our own old data
   return *this;
} // tmp will automatically be destroyed and takes our old data with it
于 2009-10-22T07:32:01.907 回答
0

from = new char[stringLen+1];应该是from.stringPtr = new char[stringLen+1];。还要记住在分配新内存之前释放先前分配的内存。

于 2009-10-22T06:21:18.520 回答
0

仔细看线

from = new char[stringLen+1];

它与

from = MyString(new char[stringLen+1]);

所以你的 MyString 构造函数得到未初始化的字符数组。然后您尝试获取字符串的长度,但strlen只是循环遍历字符串的字符以查找0字符。由于我们不知道未初始化的字符数组可能有什么内容,我们不知道strlen可以返回什么长度。它甚至可以比数组边界更进一步,并使您的程序因段错误而崩溃。但我可以肯定地说,在那之后 from.stringPtr 中没有足够的空间来保存你想要复制的字符串。

因此,使用from.stringPtr = new char[stringLen+1];或更好,from = MyString(*this);因为您已经有复制构造函数。

于 2009-10-22T06:27:09.697 回答