2011-03-16 74 views
1

上周,我们创建了一个使用类和向量来管理字符串集的程序。我能够完成这100%。本周,我们必须用简单的单链表来替换我们用于存储字符串的向量。需要复制构造函数帮助单链表的基本实现

该函数基本上允许用户声明空的字符串集合,并且只设置一个元素。在主文件中,有一个向量,其元素是一个包含setName和strSet(class)的结构。

这是我的问题:它处理类的复制构造函数。当我删除/注释掉复制构造函数时,我可以根据需要声明任意数量的空集或单集,并输出它们的值而不会出现问题。但是我知道当我执行程序的其余部分时,我显然需要使用拷贝构造函数。当我离开复制构造函数时,我可以声明一个单独的或空的集合并输出其值。但是如果我声明第二组,并且我尝试输出前两组中的任一组,我会得到一个分段错误。此外,如果我尝试声明多于两套,我会得到一个分段错误。任何帮助,将不胜感激!!

这里是我的一个非常基本实现所有的代码:

这里是setcalc.cpp:(主文件)

#include <iostream> 
#include <cctype> 
#include <cstring> 
#include <string> 
#include "strset2.h" 

using namespace std; 

// Declares of structure to hold all the sets defined 
struct setsOfStr { 
    string nameOfSet; 
    strSet stringSet; 
}; 

// Checks if the set name inputted is unique 
bool isSetNameUnique(vector<setsOfStr> strSetArr, string setName) { 
    for(unsigned int i = 0; i < strSetArr.size(); i++) { 
     if(strSetArr[i].nameOfSet == setName) { 
      return false; 
     } 
    } 
    return true; 
} 

int main() { 
    char commandChoice; 
    // Declares a vector with our declared structure as the type 
    vector<setsOfStr> strSetVec; 

    string setName; 
    string singleEle; 
    // Sets a loop that will constantly ask for a command until 'q' is typed 
    while (1) { 
      cin >> commandChoice; 
     // declaring a set to be empty 
     if(commandChoice == 'd') { 
      cin >> setName; 
      // Check that the set name inputted is unique 
      if (isSetNameUnique(strSetVec, setName) == true) { 
       strSet emptyStrSet; 
       setsOfStr set1; 
       set1.nameOfSet = setName; 
       set1.stringSet = emptyStrSet; 
       strSetVec.push_back(set1); 
      } 
      else { 
       cerr << "ERROR: Re-declaration of set '" << setName << "'\n"; 
      } 
     } 
     // declaring a set to be a singleton 
     else if(commandChoice == 's') { 
      cin >> setName; 
      cin >> singleEle; 
      // Check that the set name inputted is unique 
      if (isSetNameUnique(strSetVec, setName) == true) { 
       strSet singleStrSet(singleEle); 
       setsOfStr set2; 
       set2.nameOfSet = setName; 
       set2.stringSet = singleStrSet; 
       strSetVec.push_back(set2); 
      } 
      else { 
       cerr << "ERROR: Re-declaration of set '" << setName << "'\n"; 
      } 
     } 
     // using the output function 
     else if(commandChoice == 'o') { 
      cin >> setName; 
      if(isSetNameUnique(strSetVec, setName) == false) { 
       // loop through until the set name is matched and call output on its strSet 
       for(unsigned int k = 0; k < strSetVec.size(); k++) { 
        if(strSetVec[k].nameOfSet == setName) { 
          (strSetVec[k].stringSet).output(); 
        } 
       } 
      } 
      else { 
       cerr << "ERROR: No such set '" << setName << "'\n"; 
      } 
     } 
     // quitting 
     else if(commandChoice == 'q') { 
      break; 
     } 
     else { 
      cerr << "ERROR: Ignoring bad command: '" << commandChoice << "'\n"; 
     } 
    } 
    return 0; 
} 

这里是strSet2.h:

#ifndef _STRSET_ 
#define _STRSET_ 

#include <iostream> 
#include <vector> 
#include <string> 

struct node { 
    std::string s1; 
    node * next; 
}; 

class strSet { 

private: 
    node * first; 
public: 
    strSet(); // Create empty set 
    strSet (std::string s); // Create singleton set 
    strSet (const strSet &copy); // Copy constructor 
    // will implement destructor and overloaded assignment operator later 

    void output() const; 


}; // End of strSet class 

#endif // _STRSET_ 

这里是strSet2.cpp(cla的实现SS)

#include <iostream> 
#include <vector> 
#include <string> 
#include "strset2.h" 

using namespace std; 

strSet::strSet() { 
    first = NULL; 
} 

strSet::strSet(string s) { 
    node *temp; 
    temp = new node; 
    temp->s1 = s; 
    temp->next = NULL; 
    first = temp; 
} 

strSet::strSet(const strSet& copy) { 
    cout << "copy-cst\n"; 
    node *n = copy.first; 
    node *prev = NULL; 
    while (n) { 
     node *newNode = new node; 
     newNode->s1 = n->s1; 
     newNode->next = NULL; 
     if (prev) { 
      prev->next = newNode; 
     } 
     else { 
      first = newNode; 
     } 
     prev = newNode; 
     n = n->next; 
    } 
} 

void strSet::output() const { 
    if(first == NULL) { 
     cout << "Empty set\n"; 
    } 
    else { 
     node *temp; 
     temp = first; 
     while(1) { 
      cout << temp->s1 << endl; 
      if(temp->next == NULL) break; 
      temp = temp->next; 
     } 
    } 
} 

回答

0

这看起来有点奇特:

strSet::strSet(string s) { 
    node *temp; 
    temp = new node; 
    temp->s1 = s; 
    temp->next = NULL; 
    first = temp; 
} 

如果什么 '第一' 是指向已经有了?然后你有效地杀死之前的列表并导致mem泄漏。

+0

'first'并没有指向已经调用该函数之前的东西,因为函数是一个构造函数。 – aschepler

+0

是的,它是一个构造函数。 – Tesla

0

时,其参数为空你strSet拷贝构造函数不分配成员first。这会导致未定义的行为。

另外,在编辑之前显示的strSet赋值运算符(operator=)肯定是错误的;并且定义复制构造函数并不是一个好主意,但允许编译器隐式定义析构函数和赋值运算符。请参阅Rule of Three

实现三巨头时,他们需要(在这种情况下等)做了管理的一种常用方法看起来是这样的:在一个标准集装箱使用的类型

class strSet { 
private: 
    void cleanup(); 
    void create_from(const node* n); 
// ... 
}; 

strSet::~strSet() { cleanup(); } 

strSet::strSet(const strSet& copy) : first(NULL) { create_from(copy.first); } 

strSet& strSet::operator=(const strSet& rtSide) { 
    if (this != &rtSide) { 
     cleanup(); // trash old contents of *this 
     create_from(rtSide.first); // clone contents of rtSide 
    } 
    return *this; 
} 
+0

当声明让我们说空集(所以如果输入命令只是'd'),我不使用重载的'='运算符是否正确?我只是不确定为什么当我在一行中声明3个空集时,我总是收到分段错误。如果我声明一个,它工作正常,我可以输出它的价值。如果我声明两组,只要我尝试输出值,我会得到“分段错误”,如果我尝试声明3组,则尽快尝试获得“分段错误”。这不应该访问重载的'='操作符。 – Tesla

+0

@Jesus:找到你的其他问题并编辑我的答案。但是如果你自己没有声明一个'operator =',编译器会为你创建一个''operator =',它提供的内容不一定是安全的。 – aschepler

+0

好吧,完美!感谢您的帮助,感谢! – Tesla

1

C++标准状态(如std :: vector)必须是可复制且可赋值的。

由于您尚未在类strSet上实现自定义赋值运算符,因此编译器将为您生成一个用于执行简单成员复制的运算符。在你的情况下,这意味着'第一个'指针将被直接复制。显然这意味着两个对象现在拥有该集合中的节点,并且当它被释放两次时会发生崩溃。

一些提示:

  1. 实现自定义赋值运算符,做同样的事情,你的拷贝构造函数

  2. 通过引用传递对象阅读起来,并通过const引用在可能的情况。当你通过价值传递时,你正在做很多不必要的容器和字符串复制。

例如,

布尔isSetNameUnique(常量向量& strSetArr,常量字符串&的setName)

祝你好运:)