I study with ++, there is a question:

There is a class:

#ifndef STRING_2_H #define STRING_2_H #include <iostream> class String { private: char *str; int len; static int num_strings; static const int CINLIM = 80; public: String(const char * s); String(); String(const String &); ~String(); String & operator+(const String &); String & stringlow(); String & stringup(); int has(const char) const; bool operator==(const String &); String & operator=(const String &); friend String & operator+(const char *, const String &); friend std::ostream & operator<<(std::ostream &, const String & a); friend std::istream & operator>>(std::istream &, String &); }; #endif 

there is an implementation of the class methods, though a bit unfinished:

 #include "string2.h" #include <cstring> String::String() { str = new char[1]; *str = '\0'; len = 0; // num_strings++; } String::String(const char * s) { len = strlen(s) + 1; str = new char[len]; strcpy(str, s); // num_strings++; } String::String(const String & a) { len = a.len; str = new char[len]; strcpy(str, a.str); // num_strings++; } String::~String() { // num_strings--; //std::cout << "Dest" << num_strings << std::endl; delete [] str; } String & String::operator+(const String & a) { std::cout << "debug1"; char * buffer; buffer = new char [len + a.len + 1]; strcpy(buffer, str); String res(strcat(buffer, a.str)); delete [] buffer; std::cout << "debug1"; return res; } String & String::stringlow() { } String & String::stringup() { } int String::has(const char a) const { } bool String::operator==(const String &) { } String & String::operator=(const String & a) { if(this == &a) { return *this; } //std::cout << a; std::cout << "debug10"; len = a.len; delete [] str; str = new char[len]; strcpy(str, a.str); return *this; } String & operator+(const char *a, const String & b) { std::cout << "debug2"; } std::ostream & operator<<(std::ostream & os, const String & a) { os << a.str; return os; } std::istream & operator>>(std::istream & is, String & a) { char *buffer; buffer = new char[String::CINLIM]; is.getline(buffer, String::CINLIM); a = buffer; delete [] buffer; return is; } 

The main program is:

 #include <iostream> using namespace std; #include "string2.h" int main() { String s1(" and I am a C++ student."); String s2 = "Please enter your name: "; String s3; cout << s2; cin >> s3; std::cout << "cout"; s2 = "My name is " + s3; cout << "Bye\n"; return 0; } 

There is a compiler output

~ / workspace / learning_c ++ $ ./a.out Please enter your name: Bla terminate called after throwing an instance of 'std :: bad_alloc'
what (): std :: bad_alloc debug10coutdebug2debug10 Emergency shutdown (memory dump made)

It is not clear where the error is.

The following is not clear: we have the string s2 = "bla bla" + s3; Why is the operator called first in the console output = when the priority is lower than +? As I understand it, in c ++ there are conversion constructors - one of them is String::String(const char * s) . Why does the compiler require precisely a friendly function with charms and strings in arguments, but does not convert charms into a string and from there into the + (string) operator?

  • I can’t guess where the call from the >> operator goes when the operation is = . If we really take up classes - trace - and find the error quickly. I can say for sure that the operator >> first called in the string cin >> s3; - nick_n_a
  • Most likely you have a logical error. It affects several lines here is.getline(buffer, String::CINLIM); and here a = buffer; (operator >> constructor call) and here len = strlen(s) + 1; (constructor), and it lies in the fact that you get a "buffer" in getline, i.e. not ASCIIZ, but by making the assignment, call the methods of working with ASCIIZ. It may help to put buffer[is.getline(buffer, String::CINLIM)]=0 , but for len = 80 you catch a glitch, then you need to put it in new +1. - nick_n_a

3 answers 3

In this sentence

 s2 = "My name is " + s3; 

you call a class-friendly operator, as the most appropriate function for the given arguments, where their conversion is not required

 friend String & operator+(const char *, const String &); 

This statement is defined as follows.

 String & operator+(const char *a, const String & b) { std::cout << "debug2"; } 

This operator has no clause with return , so the program has undefined behavior when calling this operator.

It would be correct to declare this operator as

 String operator+(const char *a, const String & b); 

that is, to return a temporary object from it.

  • This was a key point of misunderstanding, thank you! - Ivan
  • @Ivan Not at all. Ask more. :) - Vlad from Moscow
  • And which compiler allows you to compile the function code that supposedly returns something without the return operator and how does this compare with the standard? - Harry
  • @Harry Practically, all compilers with which I dealt, in some cases, skip over such a definition of a function, which leads to undefined program behavior. Of course, this has nothing to do with main. - Vlad from Moscow
  • Well, from my practice I was sure that such code simply would not be compiled. Well, in the most extreme case - with huge warning letters :) It is strange that this is generally allowed - all the more so in this case it is easier to trace the violation to the compiler. And - the return of something that will not be used - as for me, there is no reason to allow such behavior in the standard. So to speak, I seek and find no excuse; I'm glad that those compilers that I had to deal with consider it an absolute error ... - Harry

Your execution goes in this order:
Two constructors from const char * .
The default constructor for s3 .
Output operator
An input statement that executes a constructor from const char * to cast and then assign.
Your output is "cout" .
Operator + . In which there is no code. It is called as ideally :) exactly matching the expression const char* + String& , while another statement would require additional type conversion.

I do not know what kind of gag you put in this assignment operator, but you have it

 String & operator+(const char *a, const String & b) 

A link to what he can return? On b ? It is impossible. constant. On the newly created string in the statement? It is impossible, this line will be destroyed, the link to nowhere. Do not return anything? :) The compiler will not miss.

This is where you keep back on us ... and you get memory problems.

Or you throw away the free concatenation operator, forcing you to use the + operator as part of a class. Which has the same problems that the compiler must honestly tell you about returning a reference to the local variable res .

  String res(strcat(buffer, a.str)); delete [] buffer; std::cout << "debug1\n"; return res; 

The variable res will be destroyed upon exit. What memory will be assigned to the assignment of a string to variable s2 ? To the released, maybe overwritten, etc. In short, undefined behavior.

So you have everything clearly - what they wrote, they got it ...

    Why does the compiler require precisely a friendly function with charms and strings in arguments, but does not convert charms into a string and from there into the + (string) operator?

    He does not require, but looks, what are the possible options. And chooses the one of them, which is better corresponds to the arguments passed. If there are several options of the same "best", it will be reported that it is impossible to select the appropriate one.