复制构造函数以获取动态分配的数组

时间:2017-05-25 23:10:14

标签: c++

尝试熟悉“规则3”并且我无法使复制构造器工作。其中一个类私有成员在值为3时返回0。

我不确定为什么在执行Copy Constructor函数时,为该类私有成员提供值0。有问题的成员是theSize,它通过class.cpp中的size()函数返回。

class.h

class Catalog {
public:
    Catalog (int maxCapacity = 100)
    int size() const;
    int capacity() const;
    void add (Book b);
    Catalog(const Catalog& c);
    ~Catalog();
    Catalog& operator= (constCatalog& c) {
        if (this != &c) {
            delete[] books;
            books = new Book[theCapacity];
            *books = *(c.books);
        }
        return *this;
    }
private:
    Book* books;
    int theCapacity;
    int theSize;
};

class.cpp

Catalog::Catalog(int maxCapacity) {
    theCapacity = maxCapacity;
    theSize = 0;
    books = new Book[theCapacity];
}

int Catalog::size() const {
    return theSize();
}

int Catalog::capacity() const {
    return theCapacity;
}

void Catalog::add (Book b)
{
    if (theSize < theCapacity || contains(b.getID())) {
        if (theSize == 0) {
            books[0] = b;
            theSize++;
        }
        else {
            if (!contains(b.getID())) {
                int i = theSize;
                for (; i && b < books[i-1]; --i) {
                    books[i] = books[i - 1];
                }
                books[i] = b;
                for (; i; --i) {
                    books[i - 1] = books[i - 1];
                }       
                theSize++;
            }
            else {
                for (int i = 0; i < theSize; ++i) {
                    if (b == books[i]) {
                        books[i] = b;
                    }
                }
            }
        }
        // Debugging only
        /*for (int i = 0; i < theSize; i++) {
            //cout << books[i] << endl;
        }*/
    }
}

bool Catalog::contains(std::string bookID) const
{
    for (int i = 0; i < theSize; ++i)
    {
        if (books[i].getID() == bookID)
            return true;
    }
    return false;
}

Catalog::Catalog(const Catalog& c) {
    books = new Book[c.theSize];
    for (int i = 0; i < c.theSize; i++) {
        books[i] = c.books[i];
}

Catalog::~Catalog() {
    delete[] books;
}

稍后在main.cpp中调用c1.size(),其中c1是另一个函数中return c的结果,通过使用调试器来自Copy Constructor,然后转到析构函数。但是,c1.size()返回0,但复制构造函数theSize = c.size()在逐步执行时的值为3

book.cpp

using namespace std;


/**
 * Create a book.
 *
 * @param id the Gutenberg ID for this book
 * @param authorInfo the author of the book
 * @param title the title of the book
 */
Book::Book (std::string theId, std::string authorInfo, std::string theTitle)
    : id(theId), authorName(authorInfo), title(theTitle)
{
}


bool Book::operator< (const Book& b) const
{
  return id < b.id;
}


bool Book::operator== (const Book& b) const
{
  return (id == b.id);
}

std::ostream& operator<< (std::ostream& out, const Book& b)
{
  cout << b.getID() << "\t"
          << b.getAuthor()  << "\t"
          << b.getTitle();
  return out;
}


std::istream& operator>> (std::istream& in, Book& b)
{
  string line;
  getline (in, line);
  if (!in.good())
    return in;
  int tab1 = line.find ("\t");
  int tab2 = line.find ("\t", tab1+1);
  string id = line.substr(0, tab1);
  string author = line.substr (tab1+1, tab2-tab1-1);
  string title = line.substr(tab2+1);
  b.setID (id);
  b.setAuthor (author);
  b.setTitle (title);
  return in;
}

的main.cpp

using namespace std;



Catalog readCatalog(const string& fileName)
{
    Catalog c;
    ifstream in (fileName);
    in >> c;
    in.close();
    return c;
}


Catalog mergeCatalogs (const Catalog& cat1, const Catalog& cat2)
{
    Catalog result (cat1.size() + cat2.size());
    int i = 0;
    int j = 0;
    while (i < cat1.size() && j < cat2.size())
    {
        Book b1 = cat1.get(i);
        Book b2 = cat2.get(j);
        if (b1.getID() < b2.getID())
        {
            result.add(b1);
            ++i;
        }
        else
        {
            result.add(b2);
            ++j;
        }
    }
    while (i < cat1.size())
    {
        result.add(cat1.get(i));
        ++i;
    }
    while (j < cat2.size())
    {
        result.add(cat2.get(j));
        ++j;
    }
    return result;
}


void mergeCatalogFiles (const string& catalogFile1, const string& catalogFile2)
{
    Catalog c1, c2;
    c1 = readCatalog(catalogFile1);
    cout << catalogFile1 << " contained " << c1.size() << " books." << endl;
    c2 = readCatalog(catalogFile2);
    cout << catalogFile2 << " contained " << c2.size() << " books." << endl;
    Catalog c3 = mergeCatalogs (c1, c2);
    cout <<  "Their merge contains " << c3.size() << " books." << endl;
    cout << c3 << flush;
}

int main (int argc, char** argv)
{
    if (argc != 3)
    {
        cerr << "Usage: " << argv[0] <<
                "catalogFile1 catalogFile2" << endl;
        return -1;
    }
    string file1 = argv[1];
    string file2 = argv[2];
    mergeCatalogFiles (file1, file2);
    if (Counted::getCurrentCount() == 0)
    {
        cout << "No memory leak detected." << endl;
        return 0;
    }
    else
    {
        cout << "Memory leak detected: " << Counted::getCurrentCount() << endl;
        return -2;
    }
}

2 个答案:

答案 0 :(得分:1)

遵循零规则:使用std::vector<Book>替换数组指针和大小。

您的容量是对尺寸的限制。

当达到容量时。使用相等的范围来找到插入的位置,替换最后一个元素然后std rotate。

在同一个类中管理资源和业务逻辑很容易出错。一次做一件事。

答案 1 :(得分:1)

尝试更像这样的东西:

class Catalog
{
public:
    Catalog (int maxCapacity = 100);
    Catalog(const Catalog& c);
    ~Catalog();

    int size() const;
    int capacity() const;

    void add (const Book &b);
    Book* find(const std::string &bookID) const;

    Catalog& operator= (Catalog c);

private:
    Book* books;
    int theCapacity;
    int theSize;

    void swap(Catalog &c);
};

#include "class.h"
#include <algorithm>

Catalog::Catalog(int maxCapacity)
{
    theCapacity = maxCapacity;
    theSize = 0;
    books = new Book[theCapacity];
}

Catalog::Catalog(const Catalog& c)
{
    theCapacity = c.theCapacity;
    books = new Book[theCapacity];
    for(int i = 0; i < c.theSize;; ++i)
        books[i] = c.books[i];
    theSize = c.theSize;
}

Catalog::~Catalog()
{
    delete[] books;
}

Catalog& Catalog::operator= (const Catalog &c)
{
    if (this != &c)
        Catalog(c).swap(*this);    
    return *this;
}

void Catalog::swap(Catalog &c)
{
    std::swap(books, c.books);
    std::swap(theSize, c.theSize);
    std::swap(theCapacity, c.theCapacity);
}

int Catalog::size() const
{
    return theSize;
}

int Catalog::capacity() const
{
    return theCapacity;
}

void Catalog::add (const Book &b)
{
    Book *book = find(b.getID());
    if (book) {
        *book = b;
    }
    else if (theSize < theCapacity)
    {
        int i;
        for (i = theSize; i && b < books[i-1]; --i) {
            books[i] = books[i - 1];
        }
        books[i] = b;
        ++theSize;
    }

    // Debugging only
    /*
    for (int i = 0; i < theSize; ++i) {
        cout << books[i] << endl;
    }
    */
}

Book* Catalog::find(const std::string &bookID) const
{
    for (int i = 0; i < theSize; ++i)
    {
        if (books[i].getID() == bookID)
            return &books[i];
    }
    return 0;
}

话虽如此,如果使用std::vector和STL算法,这将更简单,更容易管理。让STL为您努力工作:

#include <vector>

class Catalog
{
public:
    Catalog (int initialCapacity = 100);

    int size() const;
    int capacity() const;

    void add (const Book &b);
    Book* find(const std::string &bookID) const;

private:
    std::vector<Book> books;
};

#include "class.h"
#include <algorithm>

Catalog::Catalog(int initialCapacity)
{
    books.reserve(initialCapacity);
}

int Catalog::size() const
{
    return books.size();
}

int Catalog::capacity() const
{
    return books.capacity();
}

void Catalog::add (const Book &b)
{
    Book *book = find(b.getID());
    if (book) {
        *book = b;
    }
    else {
        books.insert(std::upper_bound(books.begin(), books.end(), b), b);
    }

    // Debugging only
    /*
    for (Book &book: books) {
        cout << book << endl;
    }
    */
}

Book* Catalog::find(const std::string &bookID) const
{
    auto iter = std::find_if(books.begin(), books.end(), [&bookID](const Book &b){ return (b.getID() == bookID); });
    if (iter != books.end())
        return &*iter;
    return 0;
}