由错误<note: candidate expects 1 argument, 0 provided>引发的思考

博客探讨了在C++编程中,当类没有默认构造函数时,作为哈希表值引发的错误。作者通过实例展示了即使类实现了拷贝构造函数和赋值运算符,如果缺少默认构造函数,依然可能导致问题。原因可能是哈希表在初始化时需要默认构造函数。解决方案包括保留默认构造函数或为所有参数提供默认值。此外,代码中memcpy拷贝grade数组可能导致原题无法通过。
摘要由CSDN通过智能技术生成

最近在刷PAT甲级辅导课的时候,遇到了如标题所示的错误。题目链接:1561. PAT 评测 - AcWing题库

引起错误的代码如下:

#include<bits/stdc++.h>
using namespace std;

int N,M;
// const int K = 6;


int n, k, m;
int P[K];

int K = 6;
struct stu
{
    string id;
    int grade[K];

    int total = 0;
    int count;

    //  stu()
    //  {
    //      cout << "默认构造函数执行" << endl;
    //  }



    stu(const stu& oth)
    {
        this->id = oth.id;
        memcpy(this->grade, oth.grade, 4*k);
        this->total = oth.total;
        this->count = oth.count;
        cout << "自定义拷贝构造函数执行" << endl;
    }

    stu(string _id):id(_id)
    {
        for(int i = 1; i <= k; ++i)
            grade[i] = -2;
        total = count = 0;
        cout << "自定义构造函数执行" << endl;
    }

    stu& operator = (const stu& oth)
    {
        this->id = oth.id;
        // this->grade = oth.grade;
        memcpy(this->grade, oth.grade, 4*k);
        this->total = oth.total;
        this->count = oth.count;
        return *this;

        cout << "重载的赋值操作符执行" << endl;
    }


    void calc()
    {
        for(int i = 1; i <= k; ++i)
        {
            total += max(0, grade[i]);
            count += grade[i] == P[i];
        }
    }

    bool has_submit()
    {
        for(int i = 1; i <= k; ++i)
        {
            if(grade[i] >= 0)
                return true;
        }
        return false;
    }

    bool operator < (const stu& oth)
    {
        if(this->total != oth.total)
            return this->total > oth.total;
        else if(this->count != oth.count)
            return this->count > oth.count;
        else
            return this->id < oth.id;

    }
};




int main()
{

    unordered_map<string, stu> students;

    cin >> n >> k >> m;
    for(int i = 1; i <= k; ++i) cin >> P[i];
    while(m--)
    {
        string u_id;
        int p_id, grade;
        cin >> u_id >> p_id >> grade;

        if(students.count(u_id) == 0)
            students[u_id] = stu(u_id); //引起出错的地方
        students[u_id].grade[p_id] = max(students[u_id].grade[p_id],
        grade);
    }

    vector<stu> res;
    for(auto& [fi, se]: students)
    {
        if(se.has_submit())
        {
            se.calc();
            res.push_back(se);
        }
    }
    sort(res.begin(), res.end());

    for(int i = 0, rank=1; i < res.size(); ++i)
    {
        if(i && res[i].total != res[i-1].total)
            rank = i+1;
        cout << rank << " " << res[i].id << " " << res[i].total << " ";
        for(int j=1; j <= k; ++j)
        {
            if(res[i].grade[j] == -2)
                cout << "-"  ;
            else
                cout << max(res[i].grade[j], 0) ;

            if(j < k)
                cout << " ";
        }
        cout << endl;
    }

    return 0;
}

引起错误的地方:

 按理说,在上述代码中我已经满足了C++的三五法则:完成了拷贝构造函数的自定义实现,但还是报错了。最后经过调试发现,出错的地方是因为没有默认构造函数导致的。

如下测试代码就没有问题:

#include <bits/stdc++.h>
using namespace std;

const int K = 6;
const int k = 5;
const int P[1000] = {0};
struct stu
{
    string id;
    int grade[K];

    int total = 0;
    int count;

    // stu()
    // {
    //     cout << "默认构造函数执行" << endl;
    // }

    stu(const stu &oth)
    {
        this->id = oth.id;
        memcpy(this->grade, oth.grade, 4 * k);
        this->total = oth.total;
        this->count = oth.count;
        cout << "自定义拷贝构造函数执行" << endl;
    }

    stu(string _id) : id(_id)
    {
        for (int i = 1; i <= k; ++i)
            grade[i] = -2;
        total = count = 0;
        cout << "自定义构造函数执行" << endl;
    }

    stu &operator=(const stu &oth)
    {
        this->id = oth.id;
        // this->grade = oth.grade;
        memcpy(this->grade, oth.grade, 4 * k);
        this->total = oth.total;
        this->count = oth.count;
        return *this;

        cout << "重载的赋值操作符执行" << endl;
    }

    void calc()
    {
        for (int i = 1; i <= k; ++i)
        {
            total += max(0, grade[i]);
            count += grade[i] == P[i];
        }
    }

    bool has_submit()
    {
        for (int i = 1; i <= k; ++i)
        {
            if (grade[i] >= 0)
                return true;
        }
        return false;
    }

    bool operator<(const stu &oth)
    {
        if (this->total != oth.total)
            return this->total > oth.total;
        else if (this->count != oth.count)
            return this->count > oth.count;
        else
            return this->id < oth.id;
    }
};

int main()
{
    stu A("AAA");

    stu B(A);
    stu C = A;

    return 0;
}

同样是没有默认构造函数,但是这个测试代码就能正常工作。因此初步推断当一个类对象作为哈希表的值时,该类必要要有默认的无参构造函数。并且经过调试发现:

1、无论是Windows的编译器还是linux的编译器,当一个类对象作为哈希表的值时,用该类的另一个对象对它进行初始化时,该类是先调用默认无参构造函数后再调用重载的赋值操作符,这可能跟哈希表的底层实现有关系。

2、当该类的实例对象不作为哈希表的值的时候,用一个已有的实例去初始化一个新的同类实例,无论是通过stu B(A) 还是通过stu B = A的方式都是直接走的拷贝构造函数方式。

所以在开发过程中即使类重载了多种构造函数,最好还是保留默认构造函数,多人协同开发中指不定别人会拿你的类作为哈希表的值呢。亦或者是给参数都赋默认值,这也是个可行办法。

另外,上述代码是过不了原题的,需要将上述中的拷贝构造函数和重载的复制操作符注释掉才行,原因应该是跟memcpy拷贝grade这一块代码有关系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值