Error c2106 left operand must be l value

Looking at the other questions regarding error C2106, I am still lost as to what the issue is with my code. While compiling I get the following errors: c:driver.cpp(99): error C2106: '=' : left o...

The message says that you try to assign to an expression which is not an lvalue. For built-in types, you can only assign to lvalues (that’s where the name comes from: lvalue = value that can be on the left hand side of the assignment operator, while rvalue = value that must be on the right hand side of the assignment operator).

So what is an lvalue or an rvalue? Consider the following code:

int a;
a = 3;

In this assignment a is an lvalue (if it weren’t, the compiler would complain). That is, the expression a refers to an object which can be modified. On the other hand, 3 is an rvalue, that is, basically a value. Of course you cannot assign to 3; the compiler would complain about the statement 3=a; with exactly the same message you got in your code.

So as a first approximation, an lvalue designates an object, while an rvalue designates a value. Note that this is also true for assignment of the form

a = b;

where b also is a variable. What happens here is the so-called lvalue to rvalue conversion: What is assigned is not the object b, but its current value.

Now consider the following case:

int f();
f() = 3;

Here you might argue that the function f does return an object (if you use some user-defined type, you even can see its construction/destruction). But the compiler still complains with the message you got. Why?

Well, even if you consider f to return an object, it is a temporary object which will go away immediately. So it does not make much sense to assign a value because you cannot do anything with it anyway afterwards.

Therefore here’s the second rule:

Whenever there’s an expression which produces a temporary object, C++ defines that expression as rvalue.

And now we come to the definition of MyVector::at() which you did not show, but which, according to the error message, probably looks similar to this:

template<typename T>
 T MyVector<T>::at(int i)
{
  return data[i];
}

This has essentially the same form as f above, as it also returns a T (an employee* in your case). This is why the compiler complains.

And that complaint is helpful: Even if the compiler wouldn’t complain, the code would not dio what you almost certainly intended. The return statement returns a copy of the object data[i]. Thus if the statement payment.at(i)=NULL; had compiled, what would actually happen would be the following:

  1. The internal object data[i] (or however you called it in your code) is copied and the temporary copy returned.
  2. The statement assigned that temporary copy, but leaves the original object in MyVector unchanged.
  3. The temporary copy gets destructed, leaving no trace of your assignment.

This is almost certainly not what you wanted. You wanted to change the internal object. To do so, you have to return a reference to that object. A reference refers to the object it was initialized with instead of making a copy. Correspondingly, a reference, even when returned, is an lvalue (since C++11 there’s a second type of reference which behaves differently, but we don’t need to care about that here). Your corrected function then reads

template<typename T>
 T& MyVector<T>::at(int i)
{
  return data[i];
}

and with that definition, payment.at(i)=NULL; not only compiles, but actually does what you want: Change the internally stored i-th pointer in payment to NULL.

  • Remove From My Forums
  • Question

  •  Hi All,

    class Bucket  
        {  
        public:  
            Bucket() {count=0label=-1; };  
        public: float label, count;  
     
                void displayData();  
                float getLabel();  
        }; 
    const int MAX=2000;
     Bucket ang[MAX];  

    ifstream inlabel(«Labels of Buckets.txt»);  

     

    k=0;
    float labelset;
    while(inlabel >> labelset && k<1023)
    {
     ang[k].getLabel() = labelset;
     cout << ang[k].getLabel() << endl;
     k++;
    }
    inlabel.close();  
     
     
    float Bucket::getLabel()  
    {  
        return label;  

       Why it shows»error C2106: ‘=’ : left operand must be l-value»?? I don’t really understand what it means, sicne my label is defined as a float already.

        Thanks a lot!


    Thank you for replying! I love this forum!

    • Edited by

      Saturday, August 9, 2008 12:05 AM
      typo

Answers

  • The easy fix is to have getLabel return a float& instead of a float, but then the name getLabel is a misnomer. So a better option would be to have separate member functions for getting and setting label:

    class Bucket 
    public
      Bucket() : label_(-1.0f), count_(0.0f) { } 
      float getLabel() const { return label_; } 
      void setLabel(float l) { label_ = l; } 
    private
      float label_; 
      float count_; 
    }; 

    This is common enough that it is normal to elide the ‘get’ and ‘set’ part of the names, and distinguish between the methods only by their parameters and return types:

    class Bucket 
    public
      Bucket() : label_(-1.0f), count_(0.0f) { } 
      float label() const { return label_; } 
      void label(float l) { label_ = l; } 
    private
      float label_; 
      float count_; 
    }; 

    • Marked as answer by
      Yan-Fei Wei
      Wednesday, August 13, 2008 6:50 AM

  • Remove From My Forums
  • Question

  • I have trouble finding my mistakes. I used visual studio to practice C language. I am not sure if C language works perfectly fine here, for I copy some C language program from a textbook and it doesn’t work.

    Like the one below, it is from a textbook, but the runing result show that «error C2106: ‘=’ : left operand must be l-value
    1>»  and the mistake is in sentence  «if (c == ‘ ‘||c == ‘n’||c= ‘t’)». Is anyone can help me fix the problem? Thank you.

    #include<stdio.h>

    #define IN 1
    #define OUT 0

    main()
    {
     int c, nl, nw, nc, state;

     state = OUT;
     nl = nw = nc = 0;
     while ((c = getchar()) !=EOF) {
      ++nc;
      if (c == ‘n’)
       ++nl;
      if (c == ‘ ‘||c == ‘n’||c= ‘t’)
       state = OUT;
      else if (state == OUT) {
       state = IN;
       ++nw;
      }
     }
     printf(«%d %d %dn», nl, nw, nc);
    }

    • Moved by

      Sunday, September 1, 2013 9:10 AM

Answers

  • Even though it’s not SB, that 1 is easy!  :-D

    if (c == ‘ ‘||c == ‘n’||c= ‘t’)

    At the end of that expression, you’re assigning the value ‘t’ to variable c, instead of comparing variable c to value ‘t’.

    That’s gonna happen every time c is neither ‘ ‘ nor ‘n’. In short, almost every time!

    The way C works is that any value not 0 is true. So, by making c = ‘t’, the whole condition’s gonna be evaluated as true too.

    That also means that state is gonna be = to OUT, b/c the condition above is always true, no matter what!


    Click on «Propose As Answer» if some post solves your problem or «Vote As Helpful» if some post has been useful to you! (^_^)

    • Edited by
      GoToLoop
      Sunday, September 1, 2013 2:23 AM
    • Marked as answer by
      BruceX
      Sunday, September 1, 2013 3:03 AM

Alonka

0 / 0 / 0

Регистрация: 17.04.2016

Сообщений: 18

1

24.04.2016, 17:05. Показов 5153. Ответов 31

Метки c++ (Все метки)


Добрый день! Пишу программу управления колледжом. И столкнулась с этой ошибкой.

У меня есть класс Department который имеет массив указателей на Course:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Department
{
    static Department* p_department;    
private:
    string name_department;
    long id_department; 
    Course** p_course;
    int count_course;
    Department(const Department& d);
    void operator = (const Department& d);
public: 
    Department();
    static Department* instance();
    ~Department();  
    void set(string name_department, long id_department);
    long get_id_department() const { return id_department; }
    int get_count_course() const { return count_course; }
    Course** get_p_course() { return p_course; }
    friend ostream& operator << (ostream &os, const Department* p_department);
    friend istream& operator >> (istream &is, Department* p_department);
    friend void operator += (Department* p_department,const Course& temp);
 
};

И в нем я пытаюсь перегрузить оператор += который добавляет Course в Department:

C++
1
2
3
4
5
6
7
8
9
10
11
void operator += (Department* p_department, const Course& temp)
{
    int count_course = p_department->get_count_course();
    if (!count_course)
    {
        p_department->get_p_course() = new Course*[count_course + 1]; //здесь выдает ошибку
        p_department->get_p_course()[0] = Course::instance();
        cin >> p_course[0];
        count_course++;
    }
...

Ошибка появляется тогда когда я хочу получить указатель на курсы и создать массив.

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



7275 / 6220 / 2833

Регистрация: 14.04.2014

Сообщений: 26,871

25.04.2016, 14:00

2

get_p_course() возвращает значение указателя. Естественно, ему нельзя присвоить.



1



Alonka

0 / 0 / 0

Регистрация: 17.04.2016

Сообщений: 18

25.04.2016, 16:39

 [ТС]

3

+= friend потому что я использую его в другом классе. В классе College.
И в классе College есть массив указателей Department**. И мне нужно перегрузить += чтобы так добавлять Course в Department.

Добавлено через 8 минут
И компилятор ругается из-за оператора:

Error C2803 ‘operator +=’ must have at least one formal parameter of class type

Добавлено через 2 минуты
Спасибо большое!Исправила:

C++
1
2
Course** arr=p_department->get_p_course();
arr = new Course*[count_course + 1];

Добавлено через 14 минут
Попробовала сделать так:

C++
1
2
3
4
5
6
void operator += (Department& p_department, const Course& c)
{
//...
    Course** arr=p_department.get_p_course();
    arr = new Course*[count_course + 1];
}

И тогда в классе College чтоб записать Course в Department нужно так?????

C++
1
*p_department[i] += temp;

Добавлено через 49 минут
И вот почему то в файле Department.h вылазит полно синтаксических ошибок:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#define _CRT_SECURE_NO_WARNINGS
#ifndef DEPARTMENT_H
#define DEPARTMENT_H
#include "Course.h"
#include <iostream>
#include <string>
using namespace std;
 
class Department
{
    static Department* p_department;    
private:
    string name_department;
    long id_department; 
    Course** p_course; //Error C2143 syntax error: missing ';' before '*'
                                      //Error C4430 missing type specifier - int assumed. Note: C++ does not support default-int
                                      //Error C2238 unexpected token(s) preceding ';'   
    int count_course;
    Department(const Department& d);
    void operator = (const Department& d);
public: 
    Department();
    static Department* instance();
    ~Department();  
    void set(string name_department, long id_department);
    string get_name() const { return name_department; } 
    long get_id_department() const { return id_department; }
    int get_count_course() const { return count_course; }
    Course** get_p_course() { return p_course; } //Error C2143 syntax error: missing ';' before '*'
                                                                             //Error C4430 missing type specifier - int assumed. Note: C++ does not support default-int
                                                                             //Error    C2238 unexpected token(s) preceding ';'
    void set_count_course(int count_course) { this->count_course = count_course; }  
    friend ostream& operator << (ostream &os, const Department* p_department);
    friend istream& operator >> (istream &is, Department* p_department);
    friend void operator += (Department& p_department,const Course& c); //Error C4430 missing type specifier - int assumed. Note: C++ does not support default-int
                                                                                                                   //Error  C2143 syntax error: missing ',' before '&'
 
};
 
#endif



0



7275 / 6220 / 2833

Регистрация: 14.04.2014

Сообщений: 26,871

25.04.2016, 18:08

4

Цитата
Сообщение от Alonka
Посмотреть сообщение

+= friend потому что я использую его в другом классе.

И что? Оно и без friend должно работать.
Оператор должен видеть все поля класса напрямую, поэтому get_p_course() не нужен, просто p_department.p_course.

Ошибки эти, наверное, из-за того, что не видит этот Course как тип.

А добавление в массив указателей потребует выделять память с учётом добавления, потом всё копировать, удалять старое и заменять p_course. Сделать так, как у тебя, значит потерять все данные, ещё и утечка памяти будет.



1



Alonka

0 / 0 / 0

Регистрация: 17.04.2016

Сообщений: 18

26.04.2016, 09:53

 [ТС]

5

Спасибо большое!

Разобралась вроде с operator +=:

C++
1
void operator += (const Course& c);

Но все не пойму насчет этих синтаксических ошибок в Department.h. Почему он не видит Course как тип?
Я же сделала #include "Course.h" и в самом коде он слово Course выделяет цветом как нужно. Ошибки эти появляются только после того как я хочу запустить программу.



0



7275 / 6220 / 2833

Регистрация: 14.04.2014

Сообщений: 26,871

26.04.2016, 10:01

6

Из этого фрагмента не ясно.



0



0 / 0 / 0

Регистрация: 17.04.2016

Сообщений: 18

26.04.2016, 10:09

 [ТС]

7

Цитата
Сообщение от nmcf
Посмотреть сообщение

Из этого фрагмента не ясно.

Исправила буквально только что!
Оказалось что в Course.h я сделала include «Department.h».
Удалила include «Department.h» и все заработало.

Спасибо огромное за помощь!!!Буду делать дальше.Надеюсь поможешь если еще возникнут вопросы!!

А насчет массивов указателей. Я делаю как создаю new копирую в temp добавляю еще один объект и потом обратно создаю new и копирую все туда. Ну и конечно delete. А другого способа я даже и не знаю.



0



7275 / 6220 / 2833

Регистрация: 14.04.2014

Сообщений: 26,871

26.04.2016, 10:41

8

Ну там не было ни копирования, ни освобождения, просто присваивалось.



1



Alonka

0 / 0 / 0

Регистрация: 17.04.2016

Сообщений: 18

27.04.2016, 14:07

 [ТС]

9

У меня возник один вопрос.
Как можно сделать ввод данных которые вводятся подряд через enter и потом вся скажем пачка считывается перегруженным оператором ввода.

C++
1
2
3
4
5
6
7
cout << "Please enter student details." << endl;
cout << "Name:";        
cout << "Code:";                        
cout << "Sex:";                     
cout << "Age:";
Student temp;
cin >> temp;

Добавлено через 20 минут

Цитата
Сообщение от Alonka
Посмотреть сообщение

У меня возник один вопрос.
Как можно сделать ввод данных которые вводятся подряд через enter и потом вся скажем пачка считывается перегруженным оператором ввода.

C++
1
2
3
4
5
6
7
cout << "Please enter student details." << endl;
cout << "Name:";        
cout << "Code:";                        
cout << "Sex:";                     
cout << "Age:";
Student temp;
cin >> temp;

Короче перегрузила просто по другому сам оператор ввода:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
istream& operator >> (istream &is, Student& s)
{
    cout << "Please enter student details." << endl;
    cout << "Name:";
    is >> s.name_student;
    cout << "Code:";
    is >> s.id_student;
    cout << "Sex:";
    is >> s.sex_student;
    cout << "Age:";
    is >> s.age_student;
    return is;
}

Добавлено через 3 часа 14 минут
Еще вопрос появился.
Хочу перегрузить оператор []:

C++
1
Student& operator [] (int index_student) { return *p_student[index_student]; }

И потом перегружаю оператор -= кторый удаляет Student с Course и получаю ошибку access violation reading location:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void Course::operator-=(const Student & s)
{
    Student** temp = new Student*[count_student - 1];   
    int index = s.get_p_student() - *p_student;
    for (int i = 0; i < index; i++)
    {
        temp[i] = p_student[i];
    }
    for (int i = 0; i < count_student - 1; i++)
    {
        temp[i] = p_student[i + 1];
    }
    delete[] p_student[index]; //access violation reading location
    delete[] p_student;
    p_student=temp;
}



0



7275 / 6220 / 2833

Регистрация: 14.04.2014

Сообщений: 26,871

27.04.2016, 15:11

10

А что такое p_student? Второй цикл идёт поверх первого, тогда зачем он? Учитывая, что здесь указатели, оператор [] вообще не применяется.



0



0 / 0 / 0

Регистрация: 17.04.2016

Сообщений: 18

27.04.2016, 18:23

 [ТС]

11

p_student это Student** p_student массив указателей который находиться в class Course.
Тоесть студенты которые учатся на этом курсе.
И мне надо сделать так чтоб можно было удалить студента с курса.
И для этого перегрузить оператор -= в class Course чтоб он удалял студента по индексу.



0



7275 / 6220 / 2833

Регистрация: 14.04.2014

Сообщений: 26,871

27.04.2016, 18:50

12

А почему двумерный массив? Одномерного мало, что ли, для списка студентов? get_p_student() что возвращает? Выражение в 4-й строке сомнительно.



0



Alonka

0 / 0 / 0

Регистрация: 17.04.2016

Сообщений: 18

27.04.2016, 18:55

 [ТС]

13

Student** p_student это так по условию задания.

C++
1
Student** get_p_student() const { return p_student; }



0



nmcf

7275 / 6220 / 2833

Регистрация: 14.04.2014

Сообщений: 26,871

27.04.2016, 21:25

14

Ты же эту функцию относительно Student вызываешь. Каждый Student хранит указатель на массив всех Student, что ли?

Добавлено через 3 минуты
Вот это что?

C++
1
    int index = s.get_p_student() - *p_student;

Один p_student у Course, это понятно. А у s он откуда? И здесь получается (Student** — Student*), разные указатели.



1



Alonka

0 / 0 / 0

Регистрация: 17.04.2016

Сообщений: 18

28.04.2016, 09:45

 [ТС]

15

C++
1
2
3
4
5
6
7
8
9
10
11
12
class Course
{
    static Course* p_course;    
private:
    string name_course;
    long id_course; 
    Student** p_student;
    int count_student;      
public: 
    Student** get_p_student() const { return p_student; }   
    Student& operator [] (int index_student) { return *p_student[index_student]; }
};

Тоесть get_p_student() вызывается из Course.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Student
{
    static Student* p_student;
private:
    string name_student;
    long id_student;
    char sex_student;
    int age_student;
    Course** p_course;
    int count_course;
    .
        .
        .
 
};

А это

C++
1
 int index = s.get_p_student() - *p_student;

я хочу получить индекс по которому находиться Student которого я хочу удалить.

Оператор -= получает объект s :

C++
1
*temp_course[j] -= *temp_student[k]; //это находится в College.cpp

Мы вводим id_course и id_student и если такие существуют то мы должны удалить temp_student[k].

Добавлено через 17 минут
Совсем забыла, и в Student.h есть

C++
1
Student* get_p_student() const { return p_student; }



0



nmcf

7275 / 6220 / 2833

Регистрация: 14.04.2014

Сообщений: 26,871

28.04.2016, 10:17

16

В этом фрагменте get_p_student() вызывается для s, а s — Student. Так что он возвращает?

C++
1
2
3
4
void Course::operator-=(const Student & s)
{
    Student** temp = new Student*[count_student - 1];   
    int index = s.get_p_student() - *p_student;

Ну хорошо, для чего это статическое поле? Я так и не пойму, как эта разность работает.



0



Alonka

0 / 0 / 0

Регистрация: 17.04.2016

Сообщений: 18

28.04.2016, 10:18

 [ТС]

17

Совсем забыла, и в Student.h есть

C++
1
Student* get_p_student() const { return p_student; }



0



7275 / 6220 / 2833

Регистрация: 14.04.2014

Сообщений: 26,871

28.04.2016, 10:20

18

Я прочитал. Для чего это? Какое предназначение у статического поля?



0



Alonka

0 / 0 / 0

Регистрация: 17.04.2016

Сообщений: 18

28.04.2016, 10:23

 [ТС]

19

Что каждый объект Student возвращает указатель на себя. И везде используются не объекты а только указатели на них.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Student
{
    static Student* p_student;
private:
    string name_student;
    long id_student;
    char sex_student;
    int age_student;
    Course** p_course;
    int count_course;
    Department* p_department;
    Student(const Student& s);
    void operator = (const Student& s);
public:
    Student();
    static Student* instance();
    ~Student();
    void set(string name_student, long id_student, char sex_student, int age_student); //function set
    string get_name_student() const { return name_student; }
    long get_id_student() const { return id_student; }
    char get_sex_student() const { return sex_student; }
    int get_age_student() const { return age_student; }
    Student* get_p_student() const { return p_student; }
    bool operator == (long id_student);
    void operator += (const Course& c);
    friend ostream& operator << (ostream &os, const Student* p_student);
    friend istream& operator >> (istream &is, Student& s);
    Course* operator [] (int index_course) { return p_course[index_course]; }
};



0



7275 / 6220 / 2833

Регистрация: 14.04.2014

Сообщений: 26,871

28.04.2016, 10:28

20

Указатель на себя — this, а статическое поле будет общим для все объектов класса.

Добавлено через 1 минуту
Если ты передаёшь Student в функцию, можно просто взять указатель.



0



Once again, I come seeking help from those more knowledgeable than I. Anyway, I got most of the bugs worked out of this code, but I keep getting the error C2106: ‘=’ : left operand must be l-value message when I try to run this code. Of course I am getting it on my IF statements. If someone could point out my mistake, I would really appreciate it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/*************
Program:	Asg_14.cpp
Author: 	Alan P. Matie                      
Date:       03 May 2009
Description: 
	Assignment 14 - Grade program with functions. This is the last program assignment!

	We are now at the end of the semester, so you can complete work with your grade program.
	As of week 15 (4/27), you will have completed
	·         13 labs (maximum 65 points)
	·         12 assignments includes introduction discussion (185 points)
	·         4 quizzes and 1 exam (162 points)
	Labs and assignments are worth 40% of your grade, while exams and quizzes 
	are worth 60%.
 
	Design a program to input your name, plus the total points to date of your labs, 
	assignments, and quiz/exam grades. 
	·         Then determine your grade with the weights above.
	·         For input use these codes: (L/l for labs, A/a for assignments, 
	E/e for quiz/exam, X/x for stopping).
	·         The total points to date and percentages should be constants.
	·         The output will be your overall numeric grade expressed as a percent 
	and your letter grade based on the common scale (60, 70,,,,,).
	·         Use a while loop with X/x as the value for the code to end the loop.
	o   The loop must contain only functions!
	Functions must be of the proper type and pass by value or reference as appropriate. 
	There must be functions for all tasks (input, processes, and output) or the 
	program will earn a grade of zero. 

New Concepts:
Challenges:
Last Modified:
**************/

#include <iostream>
#include <iomanip>
#include <cmath>
#include <string>
using namespace std;

// Declare constants
const double POSSIBLE_LAB = 65;
const double POSSIBLE_ASG = 185;
const double POSSIBLE_EXAM = 162;
const double ASGPCT = 0.40;
const double LABPCT = 0.40;
const double EXAMPCT = 0.60;

// Function Prototypes
void welcome();
void get_name(string& first_name, string& last_name);
void input_code(char& grade_code);
void printGrade(string first_name, string last_name, double numGrade, char letterGrade);
void get_grade(double asgGrade, double labGrade, double examGrade, char grade_code);
double calcGrade(double labScore, double asgScore, double examScore, double asgGrade, double labGrade, double examGrade, double numGrade);
void calcLetter(double numGrade, char letterGrade);


int main()
{
	// Declare variables below here
	string first_name, last_name;
	char letterGrade, grade_code;
	double numGrade, labGrade, examGrade, labScore, asgGrade;
	double asgScore, examScore;
	
	// Initialization Section for real number output. DO NOT MOVE!
	cout <<setiosflags(ios::fixed | ios::showpoint);
	cout <<setprecision(2);
	// Begin your "main processing" below here
	welcome();
	get_name(first_name, last_name);
	while (toupper(grade_code != 'X'))
	{
		input_code(grade_code);		
	}
	calcGrade(asgScore, labScore, examScore, asgGrade, labGrade, examGrade, numGrade);
	printGrade(first_name, last_name, numGrade, letterGrade);
	return 0;
}

// function definitions below here
void welcome()
{
	cout <<"Welcome to your Personal Grading Program!"<<endl<<endl;
}
void get_name(string& first_name, string& last_name)
{
	cout <<"Please enter your name"<<endl;
	cin >>first_name >>last_name;
}
void input_code(char& grade_code)
{
	cout <<"Please enter the grade code (A/a, L/l, E/e). Enter X/x to stop.==> ";
	cin >>grade_code;
}
void get_grade(double asgGrade, double labGrade, double examGrade, char grade_code)
{
	if ((toupper(grade_code) = 'A'))
	{
		cout <<"Please enter your total grade for assignments ==> ";
		cin >>asgGrade;
	}
	else if ((toupper(grade_code) = 'L'))
	{
		cout <<"Please enter your total grade for labs ==> ";
		cin >>labGrade;
	}
	else if ((toupper(grade_code) = 'E'))
	{
		cout <<"Please enter your total grade for exams ==> ";
		cin >>examGrade;
	}
}
double calcGrade(double labScore, double asgScore, double examScore, double asgGrade, double labGrade, double examGrade, double numGrade)
{
	labScore = ((labGrade / POSSIBLE_LAB) * LABPCT);
	asgScore = ((asgGrade / POSSIBLE_ASG) * ASGPCT);
	examScore = ((asgGrade / POSSIBLE_EXAM) * EXAMPCT);
	numGrade = ((labScore + asgScore + examScore) * 100);
}
void calcLetter(double numGrade, char letterGrade)
{
	if (numGrade <60)
		{
			letterGrade = 'F';
		}
		else if ((numGrade >= 60) && (numGrade <70))
		{
			letterGrade = 'D';
		}
		else if ((numGrade >= 70) && (numGrade <80))
		{
			letterGrade = 'C';
		}
		else if ((numGrade >= 80) && (numGrade <90))
		{
			letterGrade = 'B';
		}
		else 
		{
			letterGrade = 'A';
		}
}
void printGrade(string first_name, string last_name, double numGrade, char letterGrade)
{
	cout <<first_name <<" "<<last_name<<" has earned a grade of "<<numGrade<<"%"<<endl;
	cout <<"corresponding to a letter grade of: "<<letterGrade<<endl;
}

Member Avatar

11 Years Ago

I am just starting to teach myself C++ and i have no coding experience so please bear with me on this if I ask you to explain your reasoning behind your response.

My code is:

// operating with varables
#include <iostream>
using namespace std;

//declarations
char STAR;
int PRIME = 71;

//begin main body
int main ()
{
    int count, sum, ex, num;
    sum = count + PRIME; 
    num = count * 1 + 2;
    (sum + count = ex);
    ex = sum * count;
    count = 25.67;
    cout << " Count = " << count << ", Sum = " << sum << ", Prime = " << PRIME << endl;
    return 0;

}

Debug errors received:

Error   1   error C2106: '=' : left operand must be l-value (error on line in bold)
Warning 2   warning C4244: '=' : conversion from 'double' to 'int', possible loss of data

Let me know what you all think.

Edited

10 Years Ago
by Dani because:

Formatting fixed


Recommended Answers

How about:

ex=(sum+count);

?

Also the value 25.67 has a fractional part and an integer does not.
If you want the value to keep the .67, you will need to make the count a double (or other type of floating point number).

The warning you …

Jump to Post

All 4 Replies

Member Avatar


thines01

401



Postaholic



Team Colleague



Featured Poster


11 Years Ago

How about:

ex=(sum+count);

?

Also the value 25.67 has a fractional part and an integer does not.
If you want the value to keep the .67, you will need to make the count a double (or other type of floating point number).

The warning you got means the framework will convert that double to an integer and it will lose the fractional part.

Edited

11 Years Ago
by thines01 because:

clarity

Member Avatar

11 Years Ago

Error 1 error C2106: ‘=’ : left operand must be l-value (error on line in bold)

Did you mean to put the value you get after summing sum and count into ex. If so, you should do like this.

ex = sum + count;

Warning 2 warning C4244: ‘=’ : conversion from ‘double’ to ‘int’, possible loss of data

count is declared as an int, which means it can hold values like 100, 101, 102… but not 101.43 or 3.14. But here you are trying to assign 25.67 to count. This is not an error, but eventually your count will ignore 0.67 and store only 25. So, if the 0.67 is important in your case you should use data types like double or float for count

Member Avatar


MandrewP

60



Junior Poster in Training


11 Years Ago

I am just starting to teach myself C++ and i have no coding experience so please bear with me on this if I ask you to explain your reasoning behind your response.

My code is:

>     // operating with varables
>     #include <iostream>
>     using namespace std;
>     
>     //declarations
>     char STAR;
>     int PRIME = 71;
>     
>     //begin main body
>     int main ()
>     {
>       int count, sum, ex, num;
>       sum = count + PRIME; 
>       num = count * 1 + 2;
>       (sum + count = ex);
>       ex = sum * count;
>       count = 25.67;
>       cout << " Count = " << count << ", Sum = " << sum << ", Prime = " << PRIME << endl;
>       return 0;
>     
>     }
Debug errors received:
Error 1   error C2106: '=' : left operand must be l-value (error on line in bold)
Warning   2   warning C4244: '=' : conversion from 'double' to 'int', possible loss of data

Let me know what you all think.

Keep in mind that the «=» symbol is an assignment operator — NOT an equals sign. For example, if you write: x = 10; do not get into the habit of saying x equals 10! That is not what’s happening. In C++, this is a valid statement: x = x + 1; but mathematically that would be incorrect, since x cannot be equal to itself PLUS one more. Always say, «x is assigned the value of 10», or «x gets 10». It will mess you up later if you always think of the «=» sign as an equals sign — it’s not, it is an assignment operator.

Any variable, such as count or ex or sum, is a name for a memory location. If we say, «x = 10;» then we are saying «Place the value of 10 into the memory location that we call x». So any variable is a container of sorts that can hold something, and obviously that is what is required on the left hand side of an assignment operator, right? An l-value is just that, a container of sorts (memory location) that can hold a value, and that must be what is placed on the left side of an assignment operator.

Imagine that you had 3 bank accounts, and they were named sum, count and ex. And you had $50 in each account. Now, if you said to the bank teller: sum + count = ex then in essence you would be saying to transfer the $50 in your ex account and place it into your sum + count account. ??? That doesn’t make sense — left operand must be an l-value! But, if you said ex = sum + count then you would be saying «Take the $50 from my sum account and the $50 from my count account and place both in my ex account. Now that makes sense, since ex is a proper l-value, ie., one that can hold a value. Sum + count cannot hold a value, it is not a memory location, but rather is just a temporary value that is used in the middle of a calculation, and is just transient in nature. (Sum + count) is an r-value, one that goes on the right side of an assignment operator. R-values are not containers of any sort, like a memory location, but rather are just temporary values that come up in the middle of a calculation, which are soon discarded. So r-values generally go into l-values, but you had them reversed.

Just a note for clarification: ex = sum + count — here (sum + count) replaces the value in ex, it isn’t added to the existing contents of ex.

Edited

9 Years Ago
by ~s.o.s~ because:

Fixed formatting

Member Avatar


MandrewP

60



Junior Poster in Training


11 Years Ago


Reply to this topic

Be a part of the DaniWeb community

We’re a friendly, industry-focused community of developers, IT pros, digital marketers,
and technology enthusiasts meeting, networking, learning, and sharing knowledge.

Хорошо, так что, игнорируя мое ленивое кодирование (это просто для того, чтобы заставить программу работать, я уберу ее после того, как она заработает). Я настроил пару операторов if, которые будут генерировать исключения, если я не получу желаемый ввод.

#include<string>
#include<iostream>
using namespace std;

int main()
{

bool flag = false;
int month, day, year;
void header();

class monthClassException
{
public:
monthClassException()
{
message = "Invalid Month";
}
monthClassException(string str)
{
message = str;
}
string what()
{
return message;
}

private:
string message;
};
class dayClassException
{
};
class yearClassException
{
};header();

do
{
try
{
cout << "Please enter your date of birth (MM-DD-YYYY): " << endl;
cin >> month;

cin.ignore(10,'-');
cin >> day;

cin.ignore(10,'-');
cin >> year;if (month > 12 || month < 1)
throw monthClassException("Invalid Month Entry");

if( ((month == 4 || month == 6 || month == 9 || month == 11) && day > 30) || day < 1)
throw dayClassException();

else if ( ((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12 ) && day > 31) || day < 1)
throw dayClassException();

else if (month == 2 && year % 4 != 0 && day > 28)
throw dayClassException();

else if((month == 2 && year % 4 = 0) && day > 29)
throw dayClassException();
}
catch(monthClassException mCEO)
{
cout << mCEO.what() << endl;
system("pause");
}
catch(dayClassException)
{
cout << "Invalid Day Entered for Selected Month" << endl;
system("pause");
}
catch(yearClassException yCEO)
{
}
}while(!flag);return 0;
}

Я получаю свою ошибку в этом последнем исключении:

            else if((month == 2 && year % 4 = 0) && day > 29)
throw dayClassException();

он говорит, что месяц — недопустимое l-значение (почему сейчас? В самом конце, после того, как я его уже использовал — катастрофически, я признаю.) Это может быть чем-то действительно очевидным, что я не вижу, потому что я один кто это закодировал, или это может быть потому, что я действительно сумасшедший, если заявления где-то напутали.

Есть идеи?

-3

Решение

Вот ошибка:

   year % 4 = 0

ты наверное хотел написать ==

4

Другие решения

= оператор как в

year % 4 = 0

означает назначение, а не сравнение. Отсюда твоя ошибка.
Исправить это

year % 4 == 0

0

У тебя есть year % 4 = 0,
Я думаю, что у вас есть опечатка: вы можете хотеть year % 4 == 0,

Кроме того, я предпочитаю использовать скобки, чтобы сделать код более понятным:

...
else if ((month == 2) && (year % 4 == 0) && (day > 29)) {
throw dayClassException();
}

0

У вас есть оператор присваивания = в вашем состоянии вместо оператора сравнения ==,

Это довольно ясно логическая ошибка. Тем не менее, почему это компилятор ошибка? В конце концов, C ++ позволяет присваивать внутри условия, и это то, что вы могли бы законно делать.

В твоем случае, month == 2 && year % 4 = 0 обрабатывается как ((month == 2) && (year % 4)) = 0 (увидеть Приоритет оператора C ++). Это выражение в скобках оценивается как временное. Но левая часть оператора присваивания должна ссылаться на адрес памяти, на который вы можете записать ( л-значение). Таким образом, ваш код недействителен по той же причине, что 3 = 3 является недействительным. Visual Studio вызывает эту ошибку C2106.

0

В связи с этим предлагается всегда указывать константу в левой части оператора сравнения. Это помогает предотвратить логические ошибки. В качестве примера рассмотрим код

    if year == 0

и по ошибке вы написали:

    if year = 0

результат был бы логической ошибкой.
Вместо этого поместите постоянную 0 на левой стороне, так что

     if 0 = year

будет генерировать синтаксическую ошибку при компиляции, что не позволит вам совершить логическую ошибку (что может быть сложнее отладить)

0

Добавлено 18 июля 2021 в 21:56

При работе с массивами мы обычно используем оператор индекса ([]) для указания на определенные элементы массива:

myArray[0] = 7; // помещаем значение 7 в первый элемент массива

Однако рассмотрим следующий класс IntList, у которого есть переменная-член, которая является массивом:

class IntList
{
private:
    int m_list[10]{};
};
 
int main()
{
    IntList list{};
    // как получить доступ к элементам из m_list?
    return 0;
}

Поскольку переменная-член m_list является закрытой, мы не можем получить к ней доступ напрямую из переменной list. Это означает, что у нас нет возможности напрямую получать или устанавливать значения в массиве m_list. Итак, как нам получить или поместить элементы в наш список?

Без перегрузки оператора типовым методом было бы создание функций доступа:

class IntList
{
private:
    int m_list[10]{};
 
public:
    void setItem(int index, int value) { m_list[index] = value; }
    int getItem(int index) const { return m_list[index]; }
};

Хотя это работает, для пользователя это не очень удобно. Рассмотрим следующий пример:

int main()
{
    IntList list{};
    list.setItem(2, 3);
 
    return 0;
}

Мы устанавливаем элемент 2 в значение 3 или элемент 3 в значение 2? Без определения setItem() это просто непонятно.

Вы также можете просто вернуть весь список и использовать operator[] для доступа к элементу:

class IntList
{
private:
    int m_list[10]{};
 
public:
    int* getList() { return m_list; }
};

Хотя это тоже работает, синтаксически это странно:

int main()
{
    IntList list{};
    list.getList()[2] = 3;
 
    return 0;
}

Перегрузка operator[]

Однако лучшим решением в этом случае является перегрузка оператора индекса ([]), чтобы разрешить доступ к элементам m_list. Оператор индекса – это один из операторов, которые необходимо перегружать как функцию-член. Перегруженная функция operator[] всегда принимает один параметр: индекс, который пользователь помещает между квадратными скобками. В случае с нашим IntList мы ожидаем, что пользователь передаст целочисленный индекс, и в качестве результата мы вернем целочисленное значение.

class IntList
{
private:
    int m_list[10]{};
 
public:
    int& operator[] (int index);
};
 
int& IntList::operator[] (int index)
{
    return m_list[index];
}

Теперь, когда мы используем оператор индекса ([]) для объекта нашего класса, компилятор будет возвращать соответствующий элемент из переменной-члена m_list! Это позволяет нам напрямую получать и устанавливать значения m_list:

IntList list{};
list[2] = 3;                  // устанавливаем значение
std::cout << list[2] << 'n'; // получаем значение

Это легко как синтаксически, так и с точки зрения понимания. Когда вычисляется list[2], компилятор сначала проверяет, есть ли перегруженная функция operator[]. Если она есть, он передает значение внутри квадратных скобок (в данном случае 2) в качестве аргумента функции.

Обратите внимание, что хотя вы можете указать значение по умолчанию для параметра функции, на самом деле использование operator[] без индекса внутри считается недопустимым синтаксисом, поэтому в этом нет смысла.

Почему operator[] возвращает ссылку

Давайте подробнее рассмотрим, как вычисляется list[2] = 3. Поскольку оператор индекса имеет более высокий приоритет, чем оператор присваивания, list[2] вычисляется первым. list[2] вызывает функцию operator[], которую мы определили для возврата ссылки на list.m_list[2]. Поскольку operator[] возвращает ссылку, он возвращает фактический элемент массива list.m_list[2]. Наше частично вычисленное выражение становится list.m_list[2] = 3, что является простым целочисленным присваиванием.

В уроке «1.3 – Знакомство с переменными в C++» вы узнали, что любое значение в левой части оператора присваивания должно быть l-значением (которое представляет собой переменную, имеющую фактический адрес в памяти). Поскольку результат operator[] может использоваться в левой части присваивания (например, list[2] = 3), возвращаемое значение operator[] должно быть l-значением. Оказывается, ссылки всегда являются l-значениями, потому что вы можете взять ссылки только на переменные, которые имеют адреса в памяти. Итак, возвращая ссылку, компилятор удовлетворен тем, что мы возвращаем l-значение.

Подумайте, что произойдет, если operator[] вернет число int по значению, а не по ссылке. list[2] вызовет operator[], который вернет значение list.m_list[2]. Например, если бы m_list[2] имел значение 6, operator[] вернул бы значение 6. list[2] = 3 частично вычислится как 6 = 3, что не имеет смысла! Если вы попытаетесь это сделать, компилятор C++ пожалуется:

C:VCProjectsTest.cpp(386) : error C2106: '=' : left operand must be l-value

Работа с константными объектами

В приведенном выше примере IntList функция operator[] не является константной, и мы можем использовать ее как l-значение для изменения состояния неконстантных объектов. Однако что, если бы наш объект IntList был константным? В этом случае мы не сможем вызвать неконстантную версию operator[], потому что это потенциально позволит нам изменить состояние константного объекта.

Хорошая новость в том, что мы можем определять неконстантную и константную версии operator[] по отдельности. Неконстантная версия будет использоваться с неконстантными объектами, а константная версия – с константными объектами.

#include <iostream>
 
class IntList
{
private:
    // задаем классу начальное состояние для этого примера
    int m_list[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 
 
public:
    int& operator[] (int index);
    const int& operator[] (int index) const;
};

// для неконстантных объектов: может использоваться для присваивания 
int& IntList::operator[] (int index) 
{
    return m_list[index];
}

// для константных объектов: может использоваться только для доступа 
const int& IntList::operator[] (int index) const 
{
    return m_list[index];
}
 
int main()
{
    IntList list{};
    // хорошо: вызывает неконстантную версию operator[]
    list[2] = 3;
    std::cout << list[2] << 'n';
 
    const IntList clist{};
    // ошибка компиляции: вызывает константную версию operator[],
    // которая возвращает константную ссылку.
    // Ей невозможно выполнить присваивание.
    clist[2] = 3; 
    std::cout << clist[2] << 'n';
 
    return 0;
}

Если мы закомментируем строку clist[2] = 3, показанная выше программа будет компилироваться и выполняться, как ожидалось.

Проверка на ошибки

Еще одно преимущество перегрузки оператора индекса состоит в том, что мы можем сделать его более безопасным, чем прямой доступ к массивам. Обычно при доступе к массивам оператор индекса не проверяет, корректен ли индекс. Например, компилятор не будет жаловаться на следующий код:

int list[5]{};
list[7] = 3; // индекс 7 выходит за пределы массива!

Однако если мы знаем размер нашего массива, мы можем выполнить проверку в нашем перегруженном операторе индекса, чтобы убедиться, что индекс находится в пределах границ:

#include <cassert> // для assert()
 
class IntList
{
private:
    int m_list[10]{};
 
public:
    int& operator[] (int index);
};
 
int& IntList::operator[] (int index)
{
    assert(index >= 0 && index < 10);
 
    return m_list[index];
}

В приведенном выше примере мы использовали функцию assert() (включенную в заголовок cassert), чтобы убедиться, что наш индекс корректен. Если выражение внутри assert вычисляется как false (что означает, что пользователь передал недопустимый индекс), программа завершится с сообщением об ошибке, что намного лучше, чем альтернатива (повреждение памяти). Это, вероятно, наиболее распространенный метод проверки ошибок подобного рода.

Указатели на объекты и перегруженный operator[] не смешиваются

Если вы попытаетесь вызвать operator[] для указателя на объект, C++ будет считать, что вы пытаетесь указать на элемент в массиве объектов этого типа.

Рассмотрим следующий пример:

#include <cassert> // для assert()
 
class IntList
{
private:
    int m_list[10]{};
 
public:
    int& operator[] (int index);
};
 
int& IntList::operator[] (int index)
{
    assert(index >= 0 && index < 10);
 
    return m_list[index];
}
 
int main()
{
    IntList *list{ new IntList{} };
    list[2] = 3; // ошибка: это предполагает, что мы обращаемся к индексу 2 массива из IntList
    delete list;
 
    return 0;
}

Поскольку мы не можем присвоить число int объекту IntList, этот код не будет компилироваться. Однако если присваивание числа int было допустимо, этот код скомпилируется и запустится с неопределенными результатами.

Правило


Убедитесь, что вы не пытаетесь вызвать перегруженный operator[] для указателя на объект.

Правильный синтаксис – сначала разыменовать указатель (обязательно использовать круглые скобки, поскольку operator[] имеет более высокий приоритет, чем operator*), а затем вызвать operator[]:

int main()
{
    IntList *list{ new IntList{} };
    // получаем наш объект IntList, затем вызываем перегруженный operator[]
    (*list)[2] = 3; 
    delete list;
 
    return 0;
}

Это выглядит коряво и подвержено ошибкам. А еще лучше не устанавливайте указатели на свои объекты, если в этом нет необходимости.

Параметр функции не обязательно должен быть числом int

Как упоминалось выше, C++ передает то, что пользователь вводит между квадратными скобками, в качестве аргумента перегруженной функции. В большинстве случаев это будет целочисленное значение. Однако в этом нет необходимости – и на самом деле вы можете определить, чтобы ваш перегруженный operator[] принимал значение любого типа, который вам нужен. Вы можете определить свой перегруженный operator[] так, чтобы он принимал double, std::string или что угодно.

В качестве нелепого примера, чтобы вы могли убедиться, что это работает:

#include <iostream>
#include <string>
 
class Stupid
{
private:
 
public:
    void operator[] (const std::string& index);
};
 
// Нет смысла перегружать operator[], чтобы что-то напечатать,
// но это самый простой способ показать, что параметр функции
// может не быть числом int
void Stupid::operator[] (const std::string& index)
{
    std::cout << index;
}
 
int main()
{
    Stupid stupid{};
    stupid["Hello, world!"];
 
    return 0;
}

Как и следовало ожидать, этот код печатает:

Hello, world!

Перегрузка operator[] для принятия параметра std::string может быть полезна при написании определенных видов классов, например тех, которые используют слова в качестве индексов.

Заключение

Оператор индекса обычно перегружается, чтобы обеспечить прямой доступ к отдельным элементам из массива (или другой подобной структуры), содержащегося в классе. Поскольку строки часто реализуются как массивы символов, operator[] часто реализуется в строковых классах, чтобы позволить пользователю получить доступ к одиночному символу строки.

Небольшой тест

Вопрос 1

Карта (map) – это класс, в котором элементы хранятся в виде пар ключ-значение. Ключ должен быть уникальным и используется для доступа к связанной паре. В этом тесте мы собираемся написать приложение, которое позволит нам присваивать оценки студентам по именам, используя простой класс карты. Имя студента будет ключом, а оценка (в виде char) будет значением.

a) Сначала напишите структуру с именем StudentGrade, содержащую имя студента (в виде std::string) и оценку (в виде char).

Ответ

#include <string>
 
struct StudentGrade
{
    std::string name{};
    char grade{};
};

b) Добавьте класс с именем GradeMap, который содержит std::vector из StudentGrade с именем m_map.

Ответ

#include <string>
#include <vector>
 
struct StudentGrade
{
    std::string name{};
    char grade{};
};
 
class GradeMap
{
private:
    std::vector<StudentGrade> m_map{};
};

c) Напишите перегруженный operator[] для этого класса. Эта функция должна принимать параметр std::string и возвращать ссылку на char. В теле функции сначала проверьте, существует ли уже имя студента (вы можете использовать std::find_if из <algorithm>). Если студент есть, верните ссылку на оценку, и всё готово. В противном случае используйте функцию std::vector::push_back(), чтобы добавить StudentGrade для этого нового студента. Когда вы это сделаете, std::vector добавит себе копию вашего StudentGrade (при необходимости изменив размер, аннулируя все ранее возвращенные ссылки). Наконец, нам нужно вернуть ссылку на оценку студента, которого мы только что добавили в std::vector. Мы можем получить доступ к только что добавленному студенту с помощью функции std::vector::back().

Должна запуститься следующая программа:

#include <iostream>
 
// ...
 
int main()
{
    GradeMap grades{};
 
    grades["Joe"] = 'A';
    grades["Frank"] = 'B';
 
    std::cout << "Joe has a grade of " << grades["Joe"] << 'n';
    std::cout << "Frank has a grade of " << grades["Frank"] << 'n';
 
    return 0;
}

Ответ

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
 
struct StudentGrade
{
    std::string name{};
    char grade{};
};
 
class GradeMap
{
private:
    std::vector<StudentGrade> m_map{};
 
public:
    char& operator[](const std::string &name);
};
 
char& GradeMap::operator[](const std::string &name)
{
    auto found{ std::find_if(m_map.begin(), m_map.end(),
                [&](const auto& student){
                      return (student.name == name);
                }) };
    
    if (found != m_map.end())
    {
        return found->grade;
    }
 
    // в противном случае создать новый StudentGrade
    // для этого студента и добавить его в конец нашего вектора.
    m_map.push_back({ name });
 
    // и вернуть этот элемент
    return m_map.back().grade;
}
 
int main()
{
    GradeMap grades{};
 
    grades["Joe"] = 'A';
    grades["Frank"] = 'B';
 
    std::cout << "Joe has a grade of " << grades["Joe"] << 'n';
    std::cout << "Frank has a grade of " << grades["Frank"] << 'n';
 
    return 0;
}

Совет


Поскольку карты – это распространенный контейнер, стандартная библиотека предлагает std::map, который в пока не рассматривался в данной серии статей. Используя std::map, мы можем упростить наш код до следующего вида

#include <iostream>
#include <map> // std::map
#include <string>
 
int main()
{
    // std::map можно инициализировать
    std::map<std::string, char> grades{
        { "Joe", 'A' },
        { "Frank", 'B' }
    };
 
    // и присвоить
    grades["Susan"] = 'C';
    grades["Tom"] = 'D';
 
    std::cout << "Joe has a grade of " << grades["Joe"] << 'n';
    std::cout << "Frank has a grade of " << grades["Frank"] << 'n';
 
    return 0;
}

Предпочитайте использовать std::map вместо написания собственной реализации.


Вопрос 2

Дополнительный вопрос №1: Написанный нами класс GradeMap и пример программы неэффективны по многим причинам. Опишите один способ улучшения класса GradeMap.

Ответ

std::vector по своей природе не отсортирован. Это означает, что каждый раз, когда мы вызываем operator[], мы потенциально обходим весь std::vector, чтобы найти нужный элемент. С несколькими элементами это не проблема, но по мере того, как мы продолжаем добавлять имена, программа будет становиться всё медленнее. Мы могли бы оптимизировать ее, сохраняя нашу m_map отсортированной и используя бинарный поиск, так мы минимизируем количество элементов, которые нужно будет просмотреть, чтобы найти те, которые нам интересны.


Вопрос 3

Дополнительный вопрос №2: Почему эта программа не работает, как ожидается?

#include <iostream>
 
int main()
{
    GradeMap grades{};
 
    char& gradeJoe{ grades["Joe"] };     // выполняет push_back
    gradeJoe = 'A';
 
    char& gradeFrank{ grades["Frank"] }; // выполняет push_back
    gradeFrank = 'B';
 
    std::cout << "Joe has a grade of " << gradeJoe << 'n';
    std::cout << "Frank has a grade of " << gradeFrank << 'n';
 
    return 0;
}

Ответ

Когда добавляется Frank, std::vector должен вырасти, чтобы сохранить его. Это требует динамического выделения нового блока памяти, копирования элементов массива в этот новый блок и удаления старого блока. Когда это происходит, любые ссылки на существующие элементы в std::vector становятся недействительными! Другими словами, после того, как мы выполнили push_back("Frank"), GradeJoe становится висячей ссылкой на удаленную память. Это приведет к неопределенному поведению.

Теги

C++ / CppLearnCppДля начинающихОбучениеОператор (программирование)Оператор индексаПерегрузка (программирование)Перегрузка операторовПрограммирование

Понравилась статья? Поделить с друзьями:
  • Error c2099 инициализатор не является константой
  • Error c2088 недопустимо для class
  • Error c2088 illegal for class
  • Error c2086 переопределение
  • Error c2086 redefinition