- 16,110
- 8,349
Note that #include <iomanip> is the same place where you get setw(), setprecision() and the other stream manipulators that Gaddis discusses in section 3.8.
I wrote those comments for copying into my notes. I know I will forget what I am doing in the future thanks to the old brain. I just want to explain it in my notes. Actually here is the page of notes I just put in yesterday. You can see the same program with comments.sysprog said:@Mark44 maybe it's archaic of me to do so, but I put a comment on every line of my mainframe or PC assembly language code, even if what the instruction is doing is obvious or should be obvious ##-## I do that based on the it can't hurt principle ##-## if a full explanation is warranted, I'll write it on non-instruction lines ##-## otherwise, I don't see why I should unnecessarily let an unexplained instruction go by.
mov ebx, message ;Set ebx to point to the beginning of a null-terminated message string.
char[] message = "This is a message";
I miss assembly languages. I don't understand why they don't use assembly language more, it's a lot smaller, a whole hell of a lot faster. People don't need new version of software every day. I am not going to start the ranting how the newer stuffs with software and firmware are slow and all.pbuk said:In assembly language you work with registers which have fixed names and there is no such thing as a type so a comment like
is worthwhile. In a high level language, code likeCode:mov ebx, message ;Set ebx to point to the beginning of a null-terminated message string.
needs no comment, and there are at least two good reasons you should NOT add unnecessary comments.C++:char[] message = "This is a message";
I put comments on nearly all of the lines of assembly code I write, both in x86 and MIPS (the latter for the class I teach). In high-level language, comments aren't as necessary, provided that you use self-explanatory names. In any case, a comment shouldn't restate what the code is doing -- it's better to say why something is happening.sysprog said:@Mark44 maybe it's archaic of me to do so, but I put a comment on every line of my mainframe or PC assembly language code, even if what the instruction is doing is obvious or should be obvious ##-## I do that based on the it can't hurt principle ##-## if a full explanation is warranted, I'll write it on non-instruction lines ##-## otherwise, I don't see why I should unnecessarily let an unexplained instruction go by.
l = 80; // x is set to 80
const int LINE_LEN = 80; // Length of a screen line in bytes
++i; // Increments i by 1
a = a +b; // Adds b to a
--n; // Decrements n by 1
--NumberOfWidgets; // At this point NumberOfWidgets is one more
// than the last Widget. This is needed to fix this.
SpecializedPrint(a,b); // A side effect of Specialized Print is to zero *b
#include <iostream>
#include <cstring>
using namespace std;
class PersonInfo
{ private: char* name; int age; const int Nsize = 51;
public:
PersonInfo(const char* n, int a) // Constructor
{ name = new char[strlen(n)+1];
strncpy_s(name, strlen(n) + 1, n, strlen(n) + 1) ; age = a;}
PersonInfo(const PersonInfo &obj) // Copy Constructor
{name = new char[strlen(obj.name)+1];
strncpy_s(name, strlen(obj.name) + 1, obj.name, strlen(obj.name) + 1);
age = obj.age;
}
~PersonInfo() { delete[] name; }
};
int main()
{ PersonInfo bob("Bob Faraday", 32);
PersonInfo clone("clone", 44);
clone = bob;//copy constructor
return 0;
}
You have a copy constructor, but you don't have an overloaded assignment operator; i.e., operator=().yungman said:I had this program, it was working, I don't see any problem. I am blind on this, it's supposed to be simple!
clone = bob;//copy constructor needs to have operator=(), but you didn't write one.Thanks for the replyMark44 said:You have a copy constructor, but you don't have an overloaded assignment operator; i.e., operator=().
The lineclone = bob;//copy constructorneeds to have operator=(), but you didn't write one.
Also, your comment is wrong -- this line is not calling a copy constructor. A wrong comment is worse than no comment at all.
Also, your code doesn't use Nsize, so why is it there? Even if there is a good reason, it shouldn't be const int in the class definition.
The part of your code where you show the immediate window doesn't also show main(), so I'm not certain you ran the code you showed a few posts back. The part with main() is below the screen shot with the immediate window. That part also has the same incorrect comment -- "clone = bob;//copy constructor"yungman said:It's really funny, I have it in my notes that actually ran the program, you can see I can do immediate window. You look at the code, there's no assignment operator. That's where I got tripped. It obviously was working, I got everything.
Strongly agree. @yungman, packing so many statements on one line makes your code hard to follow. Please stop doing this.Jarvis323 said:I would usually avoid putting multiple statements on one line.
Also very good advice.Jarvis323 said:And I would separate statements with whitespace. Also, I would rarely put a statement on the same line as a { or }, unless it's a single line of code.
I've not heard of literate programming. Interesting concept.sysprog said:It can be hard on the ego to admit it, but I think that in his case it's not really too hard ##-## I'm convinced that Prof. Don is better at programming than I am ##-## thank you for taocp and for ##\mathrm{\TeX},## Professor, which are among the many things for which programmers and others are to be grateful to you, perhaps not the least of which is the concept of literate programming.
#include <iostream>
#include <cstring>
using namespace std;
class PersonInfo
{
private: char *name; int age; //const int Nsize = 51;
public:
PersonInfo(const char *n, int a) // Constructor
{
name = new char[strlen(n) + 1];
strncpy_s(name, strlen(n) + 1, n, strlen(n) + 1);
age = a;
}
PersonInfo(const PersonInfo &obj) // Copy Constructor
{
name = new char[strlen(obj.name) + 1];
strncpy_s(name, (strlen(obj.name) + 1), obj.name, (strlen(obj.name) + 1));
age = obj.age;
}
// Accessor functions
const char* getName() { return name; }
const int getAge() { return age; }
~PersonInfo() { delete[] name; } // Destructor
};
int main()
{
PersonInfo bob("Bob Faraday", 32);
PersonInfo clone("clone", 44);
clone = bob;//copy constructor
count << " The bob Object contains: " << bob.getName() <<
", age = " << bob.getAge() << endl;
count << " Clone object name = " << clone.getName() <<
", age = " << clone.getAge() << "\n\n";
return 0;
}
Deleted implicitly-declared copy assignment operator
A implicitly-declared copy assignment operator for class T is defined as deleted if any of the following is true:
Otherwise, it is defined as defaulted.
- T has a user-declared move constructor;
- T has a user-declared move assignment operator.
A defaulted copy assignment operator for class T is defined as deleted if any of the following is true:
https://en.cppreference.com/w/cpp/language/copy_assignment
- T has a non-static data member of non-class type (or array thereof) that is const;
- T has a non-static data member of a reference type;
- T has a non-static data member or a direct or virtual base class that cannot be copy-assigned (overload resolution for the copy assignment fails, or selects a deleted or inaccessible function);
- T is a union-like class, and has a variant member whose corresponding assignment operator is non-trivial.
I am at the process of doing that, I'll be back.Jarvis323 said:Solution is defining operator=.
Explanation: Like Mark pointed out, line 29 is not calling the copy constructor, it's calling operator=. You didn't define an operator=, so it would use the default one, which just does a shallow copy. Then when both copies go out of scope, they each call delete on the same pointer (in their destructors), which is why you get that runtime error (you should never call delete on the same address/pointer twice).
The reason it doesn't compile in the uncommented version is that C++ will "delete"
the default operator= in certain cases, forcing you to either define it yourself or not use it. Having a const member happens to be one of those conditions, as you can see in the below link under the section quoted,
// This program demonstrates the copy constructor
#include <iostream>
#include <cstring>
using namespace std;
class PersonInfo
{ private: char* name; int age; const int Nsize = 51;
public:
PersonInfo(const char* n, int a) // Constructor
{ name = new char[Nsize];
strncpy_s(name, Nsize, n, Nsize) ; age = a;}
PersonInfo(const PersonInfo &obj) // Copy Constructor
{name = new char[Nsize];
strncpy_s(name, Nsize, obj.name, Nsize);
age = obj.age;
}
PersonInfo& operator=(const PersonInfo& rhs)
{
strncpy_s(name, Nsize, rhs.name, Nsize);
age = rhs.age;
return *this;
}
// Accessor functions
const char *getName() { return name; }
const int getAge() { return age; }
const void printB() { count << " bob name: " << name
<< ", (void*)name: " << (void*)name << "\n\n"; }
const void printC() { count << " clone name: " << name <<
", (void*)name: " << (void*)name<< "\n\n"; }
void setName() { strncpy_s(name, Nsize, "delete", Nsize); }
~PersonInfo() { delete[] name; }
};
int main()
{ PersonInfo bob("Bob Faraday", 32);
PersonInfo clone("clone", 44);
clone = bob;//copy constructor
count << " The bob Object contains: " << bob.getName() <<
", age = " << bob.getAge() << endl;
count << " Clone object name = " << clone.getName() <<
", age = " << clone.getAge() << "\n\n";
bob.setName();
count << " The bob Object after setName: " << bob.getName() <<
", age = " << bob.getAge() << endl;
count << " Clone object after setName = " << clone.getName() <<
", age = " << clone.getAge() << "\n\n";
bob.printB();
clone.printC();
return 0;
}
int main()
{ PersonInfo bob("Bob Faraday", 32);
PersonInfo clone("clone", 44);
clone = bob;//copy constructor
<snip>
PersonInfo joe; // Calls a default constructor, which you don't have - compiler error
PersonInfo bob("Bob Faraday", 32); // Calls the constructor with two arguments - OK
PersonInfo fred(bob); // Calls the copy constructor - OK
joe = fred; // Calls operator=(), which you now have - OK
ThanksMark44 said:From post #55:
You really need to revise your code and your notes. The last line above is an assignment. The bob and clone objects have already been created, so that line doesn't involve any constructor. You should also move Nsize out of the class definition -- it doesn't belong there.C++:int main() { PersonInfo bob("Bob Faraday", 32); PersonInfo clone("clone", 44); clone = bob;//copy constructor <snip>
It would be a good idea for you to review the chapter in Gaddis that discusses constructors and operator overloads. Here's a short example
C++:PersonInfo joe; // Calls a default constructor, which you don't have - compiler error PersonInfo bob("Bob Faraday", 32); // Calls the constructor with two arguments - OK PersonInfo fred(bob); // Calls the copy constructor - OK joe = fred; // Calls operator=(), which you now have - OK
It's not really a variable, as it won't change when the program runs. Things like this are often called parameters (different from function parameters) or named constants. The proper place for it is outside the class, like up at the top of the program.yungman said:That's another thing, I really don't know where to put variables like Nside.
Of course it is worth your while. The main reason I teach a class or two a year is to help exercise my brain. That's also why I work the NY Time crossword puzzle every day, as well as post here at PF. These activities help to exercise my brain and keep the neurons working.yungman said:But learning a completely new thing is something else. Just hope this brain exercise ( learning C++) is worth my while like doing physical exercise!
ThanksMark44 said:It's not really a variable, as it won't change when the program runs. Things like this are often called parameters (different from function parameters) or named constants. The proper place for it is outside the class, like up at the top of the program.
One style that is used a lot for named constants is ALL CAPS. That makes them really stand out in the code. Aside from this, Nside is not a good name to use, as it seemingly represents the number of sides on some geometric figure. A better choice would be MAX_NAME_LEN or something similar.
Of course it is worth your while. The main reason I teach a class or two a year is to help exercise my brain. That's also why I work the NY Time crossword puzzle every day, as well as post here at PF. These activities help to exercise my brain and keep the neurons working.
I don't agree with that - this constant is used to specify the length of class members that are C-strings so it shouldn't be plluting the global namespace. Namespacing it is one option but probably beyond the current level of expertise (!),Mark44 said:The proper place for it is outside the class, like up at the top of the program.
static const class member// PersonInfo.h
#define PERSON_INFO_STRING_LENGTH 25