Search code examples
c++protocol-buffers

protobuf C++ issue with functions and double cout


Here is the code:

#include <iostream>
#include <fstream>
#include "Students.pb.h"



class IRepository {
    virtual void Open() = 0; // binary decerialization 
    virtual void Save() = 0; // binary serialization
};


class IMethods {
    virtual double GetAverageScore(const FullName& name) = 0;
    virtual std::string GetAllInfo(const FullName& name) = 0;
    virtual std::string GetAllInfo() = 0;
};

StudentsGroup group1;


class StudentGroup : public IRepository, public IMethods
{
public:
    void Open() override
    {
        std::fstream in("D:\GeekBrains CPP\diff moments 7\studentsgroup.bin", std::ios_base::binary);
        group1.ParseFromIstream(&in);
        if (!group1.ParseFromIstream(&in))
        {
            std::cout << "Open error!" << std::endl;
        }


    }

    void Save() override
    {
        std::fstream out("D:\GeekBrains CPP\diff moments 7\studentsgroup.bin", std::ios_base::binary);
        group1.SerializeToOstream(&out);
        
    }

   double GetAverageScore(const FullName& name) override
    {
       int i = 0;
       double average;
       for (const auto& student : group1.sinfo())
       {
           if (student.sname().surname() == name.surname() && student.sname().name() == name.name())
           {
               std::cout << "Average score is: " << student.averagemark();
               average = student.averagemark();
               i++;
           }
       }

       if (i == 0)
       {
           std::cout << "No such student has been found!" << std::endl;
       }
       else if (i >= 2)
       {
           std::cout << "There're more then 1 student with this surname!" << std::endl;
       }
       return average;
    }

   std::string GetAllInfo(const FullName& name) override
    {   
       int i = 0;
        for(const auto& student : group1.sinfo())
        {
            if (student.sname().surname() == name.surname() && student.sname().name() == name.name())
            {
                std::cout << "Full Name: " << student.sname().surname() << " " << student.sname().name() << " " << student.sname().patronymic() << \
                    " marks: " ;
                for (auto mark : student.grade())
                {
                    std::cout << mark << "";
                }
                std::cout << "average mark: " << student.averagemark();
                i++;
            }

        }

        if (i == 0)
        {
            std::cout << "No such student has been found!" << std::endl;
        }
        return {};
    }

    std::string GetAllInfo() override
    {
        for (const auto student : group1.sinfo())
        {
            std::cout << "Full Name: " << student.sname().surname() << " " << student.sname().name() << " " << student.sname().patronymic() << \
                " marks: ";
            for (auto mark : student.grade())
            {
                std::cout << mark << " ";
            }
            std::cout << "average mark: " << student.averagemark() << std::endl;
        }

        if (group1.sinfo_size() == 0)
        {
            std::cout << "There're no students in the group yet" << std::endl;
        }
        return {};
    }


};



double average(const google::protobuf::RepeatedField<int32_t>& grades)
{
    double s = 0;
    for (const int& i : grades)
    {
        s += i;
    }
    return round((s / grades.size())*100)/100;
}


int main()
{
    auto name1 = std::make_unique<FullName>();
    name1->set_surname("Sergeev");
    name1->set_name("Sergey");
    name1->set_patronymic("Sergeevich");
    

    auto student1 = std::make_unique<Student>();
    student1->set_allocated_sname(name1.release());
    student1->add_grade(5);
    student1->add_grade(4);
    student1->add_grade(4);
    student1->set_averagemark(average(student1->grade()));
    std::cout << student1->averagemark() << std::endl;
    

    
    group1.mutable_sinfo()->AddAllocated(student1.release());
    for (auto i : group1.sinfo())
    {
        std::cout << "Full Name: " << i.sname().surname() << " " << i.sname().name() << " " << i.sname().patronymic() << \
            " marks: ";
        for (auto mark : i.grade())
        {
            std::cout << mark << " ";
        }
         std::cout << "average mark: " << i.averagemark() << std::endl;
    }

    StudentGroup sg1;
    sg1.GetAllInfo();
    **sg1.GetAverageScore(student1->sname());**

}

and here is proto file:

syntax="proto3";

message FullName{
    string Surname = 1;
    string Name = 2;
    optional string Patronymic = 3;
}

message Student{
    FullName sName = 1;
    repeated int32 Grade = 2;
    double AverageMark = 3;
}

message StudentsGroup{
    repeated Student sInfo = 1;
}

I have several issues I can't resolve:

  1. When I cout averagemark with function GetAllInfo() or i.averagemark(), I get some rubbish but in case where I cout it as student1->averagemark() it worked well. How do I solve it?
  2. I don't know how to enter arguments in functions double GetAverageScore(const FullName& name) override and std::string GetAllInfo(const FullName& name) override. Nothing I do seems to work. I get an exception:
    inline const ::FullName& Student::_internal_sname() const {
      const ::FullName* p = _impl_.sname_;
      return p != nullptr ? *p : reinterpret_cast<const ::FullName&>(
          ::_FullName_default_instance_);
    

I'm new to programming so appreciate any help. Thanks!


Solution

  • student1 is a smart pointer and holds nullptr after student1.release() in

    group1.mutable_sinfo()->AddAllocated(student1.release());
    

    The student1 is owned by group1 since that moment. Call them

    sg1.GetAverageScore(group1.sinfo(0).sname());
    sg1.GetAllInfo(group1.sinfo(0).sname());