使用指向类对象的指针作为多图示例中的键

时间:2016-03-21 15:39:55

标签: c++ pointers multimap

我已经阅读了很多内容,但我似乎无法理解这应该如何运作。此程序最初使用的是成员multimap<CFile, Filetype>,但我需要将其重新命名为multimap<CFile*, Filetype>。根据我对指针的小小理解,我需要创建一个multimap,它指向CFile个对象作为键,但是我没有实现它。我实际上在CDirectory构造函数中将指针放在multimap中,但是当我尝试打印CDirectory的一个对象时,程序崩溃,因此{(1)} ostream operator<<重载CDirectory class CFile { string m_strFile; unsigned int m_size; public: /*constructors, get() and set() functions are implemented but I've deleted them for the example */ bool operator< (const CFile& obj) const { return (m_strFile < obj.m_strFile); } bool operator== (const CFile& obj) const { return (m_size == obj.m_size); } friend ostream& operator<< (ostream& ost, const CFile& obj) { return ost << "name: " << obj.m_strFile << ", size: " << obj.m_size; } friend istream& operator>> (istream& ist, CFile& obj) { return ist >> obj.m_strFile >> obj.m_size; } }; class CDirectory { string m_strDirectory; enum class Filetype { Archive, Hidden, ReadOnly, System, FileNotSupported }; multimap <CFile*, Filetype> m_DirectoryMap; public: /* overloading operator<< for class CDirectory and uses the friend function filetypeToString to convert the enum value to string */ friend std::ostream& operator<<(std::ostream &os, const CDirectory &dir) { os << dir.m_strDirectory << "\n"; auto p = m_DirectoryMap.begin(); while ( p != m_DirectoryMap.end()) { os << p->first->getFileName() << '\t' << p->first->getFileSize() << '\t' << CDirectory::filetypeToString(p->second) << '\n'; ++p; } return os; } /* comparator function, used to find the min and max files by size - takes 2 pairs of the multimap and compares their CFile objects filesize */ static bool Greater(const pair<const CFile, Filetype>& a, const pair<const CFile, Filetype>& b) { return (a.first.getFileSize() < b.first.getFileSize()); } /* explicit constructor - reads data from a file and inserts pairs of types pair <CFile, enum Filetype> in a multimap */ CDirectory (const string& n) { fp.open (n, ios::in); if (!fp) { throw std::runtime_error("Could not open file"); } string dirName, fileName, fType; int fileSize; Filetype filetype; fp >> dirName; m_strDirectory = dirName; while (fp >> fileName >> fileSize >> fType) { CFile obj (fileName, fileSize); CFile* ptr = &obj; if (fType == "Archive") filetype = Filetype::Archive; else if (fType == "Hidden") filetype = Filetype::Hidden; else if (fType == "ReadOnly") filetype = Filetype::ReadOnly; else if (fType == "System") filetype = Filetype::System; else filetype = Filetype::FileNotSupported; m_DirectoryMap.insert(pair<CFile*, Filetype>(ptr, Filetype(filetype))); } } string getDirectory () const { return m_strDirectory; } void printMap () { auto p = m_DirectoryMap.begin(); cout << m_strDirectory << endl; while ( p != m_DirectoryMap.end()) { cout << endl << p->first->getFileName() << '\t' << p->first->getFileSize() << '\t' << filetypeToString(p->second) << endl; ++p; } } int countDuplicates( const string& strToCount ) const { CFile obj (strToCount, 0); CFile* ptr = &obj; int numberOfDuplicates = m_DirectoryMap.count(ptr); if (numberOfDuplicates > 1) return numberOfDuplicates; else if (numberOfDuplicates == 1) return 1; else return 0; } void removeDuplicates( const string& strToRemove ) { CFile obj (strToRemove, 0); CFile* ptr = &obj; pair <multimap<CFile*,Filetype>::iterator, multimap<CFile*,Filetype>::iterator> range; range = m_DirectoryMap.equal_range(ptr); auto it = range.first; ++it; while (it != range.second) it = m_DirectoryMap.erase(it); } /* CFile findMaxSize() const { multimap<CFile*, Filetype>::const_iterator result; result = std::max_element(m_DirectoryMap.begin(), m_DirectoryMap.end(), Greater); CFile obj(result.first->getFileName(), result.first->getFileSize()); return obj; } CFile findMinSize() const { multimap<CFile*, Filetype>::const_iterator result; result = std::min_element(m_DirectoryMap.begin(), m_DirectoryMap.end(), Greater); CFile obj(result.first->getFileName(), result.first->getFileSize()); return obj; } */ static std::string filetypeToString(Filetype type) { switch (type) { case Filetype::Archive: return "archive"; break; case Filetype::Hidden: return "hidden"; break; case Filetype::ReadOnly: return "read-only"; break; case Filetype::System: return "system"; break; case Filetype::FileNotSupported: return "not-supported"; break; } } }; int main () { /* - Catching if the file exists, prompt the user untill a correct name is given - Making an object of type CDirectory, reading data from a file and inserting pairs of <CFile, Filetype> in a multimap. - Counting the number of duplicated filenames and removing them (leaving only 1). - Finding the min and max files by size and printing their objects. */ string filename = ""; int numberOfDuplicates = 0; cout << "Please enter input file name: \n"; string iname = ""; bool done = false; CDirectory obj(); while (!done && cin >> iname) { ifstream ist{iname}; try { CDirectory obj(iname); done = true; cout << "The original multimap (ordered by filename) contains the following data: \n\n"; system("pause"); cout << obj; cout << "\n\nCheck if the file has any duplicates. Enter a filename:\n\n"; do { cin >> filename; numberOfDuplicates = obj.countDuplicates(filename); if ( numberOfDuplicates > 1) { cout << "The file has " << numberOfDuplicates << " duplicates."; cout << "Removing duplicates of " << filename << ". \n\n"; } else if (numberOfDuplicates == 1) cout << "The file " << filename << " does not have any duplicates.\n\n"; else if (numberOfDuplicates == 0) cout << "The file " << filename << " is not in the multimap. Please enter a new filename:\n\n"; } while (!(numberOfDuplicates > 0)); system("pause"); obj.removeDuplicates(filename); cout << "The updated multimap (ordered by filename) contains the following data: \n\n"; cout << obj; } catch (std::exception &ex) { std::cout << ex.what() << "!\n" << "Please try again.\n"; } } getch(); return 0; } } .class。我真的不知道从哪里开始,我得到了基本的指针逻辑,但似乎我无法实现它。

ln -s /opt/intel/mediasdk/lib64/iHD_drv_video.so /usr/local/lib/dri/i965_drv_video.so

1 个答案:

答案 0 :(得分:0)

while (fp >> fileName >> fileSize >> fType) {
    CFile obj (fileName, fileSize);
    CFile* ptr = &obj;
    if (fType == "Archive")
        filetype = Filetype::Archive;
    else if (fType == "Hidden")
        filetype = Filetype::Hidden;
    else if (fType == "ReadOnly")
        filetype = Filetype::ReadOnly;
    else if (fType == "System")
        filetype = Filetype::System;
    else
        filetype = Filetype::FileNotSupported;
    m_DirectoryMap.insert(pair<CFile*, Filetype>(ptr, Filetype(filetype)));
}

使用

创建循环局部变量obj
CFile obj (fileName, fileSize);

然后使用

存储指向该对象的指针
CFile* ptr = &obj;
//...
m_DirectoryMap.insert(pair<CFile*, Filetype>(ptr, Filetype(filetype)));

然后再次开始循环。不幸的是,当你到达循环的末尾时,所有循环对象都被销毁,然后在循环开始时重新开始它们。这意味着地图现在有一个指向被销毁对象的指针。该指针不再有效,使用它是未定义的行为。

快速修复是创建指针而不是像

这样的自动对象
CFile* obj = new CFile(fileName, fileSize);

然后将该指针存储在地图中。这意味着您需要清理完成地图后分配的内存。您需要遍历地图并在每个键上调用delete

我们在使用

时遇到了另一个问题
multimap <CFile*, Filetype> m_DirectoryMap;

地图将按指针所在的地址对键进行排序,而不是指向CFile。要使地图按实际CFile排序,您需要编写一个自定义比较器,该比较器需要两个CFile*并返回指向CFile的比较。