Scheduling Algorithm : First Come First Serve I am practicing opearator overloading and to write copy constructor. I have written this program of scheduling algoritrhm. Please suggest me some improvements.

#include &lt;iostream&gt;
#include &lt;vector&gt;

class Scheduling
{
    int process;
    std::vector&lt;int&gt; burst_time;
    std::vector&lt;int&gt; waiting_time;

  public:
    Scheduling() : process(0) {}
    Scheduling(int n) : process(n)
    {
        for (int i = 0; i &lt; n; i++)
        {
            std::cout &lt;&lt; "Enter Burst time for process " &lt;&lt; i+1 &lt;&lt; " : ";
            int val;
            std::cin &gt;&gt; val;
            burst_time.push_back(val);
        }
    }

    //copy constructor
    Scheduling(const Scheduling &amp;other)
    {
        process = other.process;
        int size = other.burst_time.size();

        for (int i = 0; i &lt; size; i++)
        {
            burst_time.push_back(other.burst_time[i]);
        }
    }

    //copy assignment
    Scheduling &amp;operator=(const Scheduling &amp;other)
    {
        process = other.process;
        int size = other.burst_time.size();

        for (int i = 0; i &lt; size; i++)
        {
            burst_time.push_back(other.burst_time[i]);
        }

        return *this;
    }

    std::vector&lt;int&gt; cal_waiting_time(std::vector&lt;int&gt;&amp; burst_time)
    {
        waiting_time.push_back(0);

        for (int i = 0; i &lt; burst_time.size() - 1; i++)
        {
            waiting_time.push_back(waiting_time[i] + burst_time[i]);
        }
        return waiting_time;
    }

    void print_table()
    {
        waiting_time = cal_waiting_time(burst_time);
        std::cout &lt;&lt; "Process\t Burst Time\t Waiting Time\n";
        for (int i = 0; i &lt; burst_time.size(); i++)
        {
            std::cout &lt;&lt; i+1 &lt;&lt; "\t\t " &lt;&lt; burst_time[i] &lt;&lt; "\t\t " &lt;&lt; waiting_time[i] &lt;&lt; "\n";
        }
    }
};

int main()
{
    int num;
    std::cout &lt;&lt; "Enter number of process\n";
    std::cin &gt;&gt; num;
    Scheduling batch1(num);
    batch1.print_table();

    Scheduling batch2(batch1);
    batch2.print_table();
}
int process;

  public:
    Scheduling() : process(0) {}
    Scheduling(int n) : process(n) { /* ... */ }


When initializing constant values for member data, prefer in-class member initializers.

Use reasonably descriptive names. For new users, is process a count? An id? They have to dig through the code to understand that it represents the number of processes stored.  Do you need process? Can you get by with the size of burst_time?

    std::size_t process_count {0};

  public:
    Scheduling() = default;

    Scheduling(std::size_t number_of_processes) 
    : process_count (number_of_processes) 
    { /* ... */ }




    std::vector&lt;int&gt; burst_time;
    std::vector&lt;int&gt; waiting_time;


burst_time and waiting_time would benefit from stronger typing.  Prefer duration types over int.



        for (int i = 0; i &lt; n; i++)
        {
            std::cout &lt;&lt; "Enter Burst time for process " &lt;&lt; i+1 &lt;&lt; " : ";
            int val;
            std::cin &gt;&gt; val;
            burst_time.push_back(val);
        }


Compiling with warnings would have caught the signed/unsigned comparison mismatch.

You should check to see if reading from std::cin was successful.



    Scheduling(const Scheduling &amp;other)
    {
        process = other.process;
        int size = other.burst_time.size();

        for (int i = 0; i &lt; size; i++)
        {
            burst_time.push_back(other.burst_time[i]);
        }
    }


When you need to initialize a member variable with a non-constant value in a constructor, prefer initialization instead of assignment.

    Scheduling(const Scheduling &amp;other)
    : process{other.process}
    , burst_time{other.burst_time}
    , waiting_time{other.waiting_time}
    {}


Since each member variable has a well-defined copy behavior, we can use the compiler-generated copy constructor.

    Scheduling(const Scheduling &amp;) = default;




    Scheduling &amp;operator=(const Scheduling &amp;other)
    {
        process = other.process;
        int size = other.burst_time.size();

        for (int i = 0; i &lt; size; i++)
        {
            burst_time.push_back(other.burst_time[i]);
        }

        return *this;
    }


Use const to define objects with values that do not change after it has been constructed.

        const int size = other.burst_time.size();


Your copy assignment is actually a copy append.  You forgot to clear the existing list before copying.



Obey the rule of five/zero.  In C++, there are six special member functions.  Ignoring the default constructor, the rules cover the following member functions: 


Destructor
Copy Constructor
Move Constructor
Copy Assignment Operator
Move Assignment Operator


The rule of five is simple.  If you define, =default, or =delete any of these five special member functions, you should consider how the other special member functions operate in the class.  

The rule of five defaults goes a step further.  If you define, =default, or =delete any of the five special member functions, then explicitly define, =default, or =delete them all.

    class Scheduling {
        ...
      public:
        Scheduling() = default;
        Scheduling(int);

        ~Scheduling() = default;                            
        Scheduling(Scheduling const&amp;) { ... }
        Scheduling(Scheduling &amp;&amp;) = default;                
        Scheduling&amp; operator=(Scheduling const&amp;) { ... }
        Scheduling&amp; operator=(Scheduling &amp;&amp;) = default;     

        void print_table() { ... }
        std::vector&lt;int&gt; cal_waiting_time(std::vector&lt;int&gt;) { ... }
    };            


The rule of zero is just as simple.  If you can avoid defining all of the special members, then do so.  As it turns out, the compiler generated behavior of the copy, move, and destruct operations are well-defined for your member variables and consistent in their use. You do not need to define these operations yourself.

    class Scheduling {
        ...
      public:
        Scheduling() = default;
        Scheduling(int) { ... };

        void print_table() const { ... }
        std::vector&lt;int&gt; cal_waiting_time(std::vector&lt;int&gt;) { ... }
    };




    std::vector&lt;int&gt; cal_waiting_time(std::vector&lt;int&gt;&amp; burst_time)
    {
        waiting_time.push_back(0);

        for (int i = 0; i &lt; burst_time.size() - 1; i++)
        {
            waiting_time.push_back(waiting_time[i] + burst_time[i]);
        }
        return waiting_time;
    }


Know your algorithms.  See std::partial_sum.

On multiple calls, the new results do not overwrite the old results.  Instead, the new results are appended to the old results.

Did you intend for this function to be a part of the public api for this class?  Have you considered returning a cached waiting_time rather than recalculating the partial sum on each call?



    void print_table()
    {
        waiting_time = cal_waiting_time(burst_time);
        std::cout &lt;&lt; "Process\t Burst Time\t Waiting Time\n";
        for (int i = 0; i &lt; burst_time.size(); i++)
        {
            std::cout &lt;&lt; i+1 &lt;&lt; "\t\t " &lt;&lt; burst_time[i] &lt;&lt; "\t\t " &lt;&lt; waiting_time[i] &lt;&lt; "\n";
        }
    }


This function isn't being truthful in what it does.  It recalculates the waiting_time on every call which means its doing more than "print".  Consider an alternative design, such as calculating the partial sum on construction.