What are the differences between C-string and new char[] constructors in C++?

  • Thread starter Thread starter yungman
  • Start date Start date
AI Thread Summary
The discussion focuses on the differences between using C-strings and dynamic memory allocation with `new char[]` in C++ constructors. The first constructor copies a C-string into a fixed-size array, while the second allocates memory dynamically, requiring a destructor to manage memory. Participants note that both constructors can achieve deep copying, but the dynamic allocation introduces complexity without clear advantages when fixed sizes are sufficient. The conversation highlights the importance of understanding memory management and the implications of using pointers versus fixed arrays in class design. Ultimately, using fixed-length arrays simplifies the code by avoiding the need for custom destructors and copy constructors.
  • #51
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,
I am at the process of doing that, I'll be back.

Thanks
 
Technology news on Phys.org
  • #52
  • #53
@Vanadium 50 also very nice, Sir
 
  • #54
@Mark44 you are regularly awesome
 
  • #55
I put in the operator=() and it works. Don't understand why it worked so far without the operator=().

This is the program:
C++:
// 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() { cout << " bob name: " << name
       << ",   (void*)name: " << (void*)name << "\n\n"; }
   const void printC() { cout << " 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
    cout << " The bob Object contains: " << bob.getName() <<
        ", age = " << bob.getAge() << endl;
    cout << " Clone object name = " << clone.getName() <<
        ", age = " << clone.getAge() << "\n\n";
    bob.setName();
    cout << " The bob Object after setName: " << bob.getName() <<
        ", age = " << bob.getAge() << endl;
    cout << " Clone object after setName = " << clone.getName() <<
        ", age = " << clone.getAge() << "\n\n";
    bob.printB();
    clone.printC();
    return 0;
}

This is the printout from the program:
Pointer to address.jpg


maybe it's time to move on instead of keep asking why, just follow the rule of Three.

Thanks Mark, Jarvis323 and Sysprog.

Thanks
 
Last edited:
  • #56
From post #55:
C++:
int main()
{    PersonInfo bob("Bob Faraday", 32);
    PersonInfo clone("clone", 44);
    clone = bob;//copy constructor
    <snip>
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.

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
 
  • Like
Likes yungman and Vanadium 50
  • #57
Mark44 said:
From post #55:
C++:
int main()
{    PersonInfo bob("Bob Faraday", 32);
    PersonInfo clone("clone", 44);
    clone = bob;//copy constructor
    <snip>
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.

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
Thanks

That's what I've been doing the last week, revising the constructors, copy constructor and all that. I know it's important. I read through the two chapter again carefully.

That's another thing, I really don't know where to put variables like Nside. What is the rule where to put variables? I know you put in private if you don't want to change it by outside, but what's the difference between putting in public or outside the class definition? How do I know it doesn't belong there. It is more than I should or should not, Compiler sometimes gives error if it is put in the wrong place. I don't recall the book ever talk about this, it's like hit and miss for me!

Thanks for all your help. This C++ really get me on my weakest part...memorize all the rules, functions and all that. There are so so many rules. My memory is really deteriorating now, it's like in test if you call out 3 numbers and want me to repeat it, I might have problem remembering that now. I had test before that I can remember 10+ numbers. I would never past the cognitive test now! So many time you ask whether I read the replies from you guys...I did, just forgot! It's really a struggle. This is so different from electronics. The theory and stuffs in electronics are very difficult to understand, BUT we don't have a lot. Once you understand and practice, you can get good at it over time and not a whole lot to remember. This C++ have so many things to remember, anyone of them are easy, but just have so many. Like I have to keep reminding me to put const in the argument for Copy Constructor and Constructor for the rhs, then the Rule of Three. I spent a bigger part of yesterday struggling on the program that you called out I missed the Assignment. That's in the Rule of Three that I learn the day before and forgot!

It's like Calculus, You can sum up the first two semester in the front two pages and back two pages in most of the Calculus books. Hell, add another two pages, you can put the multi-variables 3rd semester in already. Try putting the essential stuffs of C++ in the first pages of the book, it's going to be a long one. Nothing difficult, just a lot of it. Pointers is one of the subject that doesn't have a lot to remember, but it has the twist and turn that it's difficult to really gets it.

In a way, C++ is good for me, really challenge my memory that I won't get if I keep working on electronics. Those I remember from before and have no problem remember and using them, I can do all the twisting and turning with it even now. But learning a completely new thing is something else. Just hope this brain exercise ( learning C++) is worth my while like doing physical exercise!

Thanks
 
Last edited:
  • #58
yungman said:
That's another thing, I really don't know where to put variables like Nside.
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.
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!
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.
 
  • Like
Likes yungman
  • #59
Mark44 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.
Thanks

So if it is declared const, I should put in global?

Ha ha, try learning something that you don't know! Like what I am doing, C++ is so much more than Pascal, after like chapter 4, it's all new to me. That's the reason I take a break from electronics. My former company asked me to do a contract for a year and half in 2015, I did not miss a beat working. Then designed two guitar amps and then a few audiophile power amps successfully. Nothing is like learning C++ that I don't know. Electronics to me is more like muscle memory, a lot of it is automatic even thought it's in a different field. Maybe it's like you learning another language, it would be very easy as you already know how programming is.

I hope C++ can shake out more rust from my brain. My English is too bad to even try cross word puzzle.
 
  • #60
Mark44 said:
The proper place for it is outside the class, like up at the top of the program.
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 (!), otherwise I don't see anything wrong with making it a static const class member.

Edit: on second thoughts as this value is only used at compile time I would make it a macro e.g.
C++:
// PersonInfo.h
#define PERSON_INFO_STRING_LENGTH 25
 
Last edited:
  • #61
Mark44 said:
From post #55:
C++:
int main()
{    PersonInfo bob("Bob Faraday", 32);
    PersonInfo clone("clone", 44);
    clone = bob;//copy constructor
    <snip>
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.

...
I finished updating my notes on Constructor and Copy Constructor. Here is the copy of this part of my notes. Obviously I really packed the lines to make the code take up less space. It's for my own notes.

Thanks
 

Attachments

  • #62
yungman said:
I finished updating my notes on Constructor and Copy Constructor. Here is the copy of this part of my notes.
The notes still have incorrect comments.
int main(){ PersonInfo bob("Bob Far", 32); PersonInfo clone("clone", 44); clone = bob;//copy constructor
bob.setName();//After copying clone = bob, change name of bob and see what happen to clone
bob.printB(); clone.printC(); return 0;}
The line clone = bob; is NOT calling a copy constructor. For about the fourth time, this code calls operator=().
The second highlighted comment above implies that you think clone changed because of a copy constructor.
yungman said:
Obviously I really packed the lines to make the code take up less space. It's for my own notes.
Why do you care about taking up less space? Packing everything in there makes it much harder for anyone, including you, to read and comprehend. Do yourself a favor and spread things out more.
 
  • Like
Likes Vanadium 50 and pbuk
  • #63
Mark44 said:
The line clone = bob; is NOT calling a copy constructor. For about the fourth time, this code calls operator=().
The second highlighted comment above implies that you think clone changed because of a copy constructor

This may be a good case for over-commenting, because the comment makes the misunderstanding clearer.

yungman, this is covered on page 820 in Gaddis (6th edition). You may wish to review it.
 
  • #64
to add:

Is it clear what the difference here is between o2 and o3 and how they are filled?

C++:
Object o1, o2;
o2 = o1;
Object o3 = o1;
 
  • #65
Mark44 said:
The notes still have incorrect comments.

The line clone = bob; is NOT calling a copy constructor. For about the fourth time, this code calls operator=().
The second highlighted comment above implies that you think clone changed because of a copy constructor.
Why do you care about taking up less space? Packing everything in there makes it much harder for anyone, including you, to read and comprehend. Do yourself a favor and spread things out more.

//The copy constructor must be left from old notes, I understand perfectly clone = bob is assignment. I emphasis in my notes of the Rule of Three. That's where it's important, to use Copy Constructor and Assignment if there is pointer in the class.

I know perfectly well Copy Constructor ONLY help with copying class object with pointers, that Copy Constructor will copy pointers that points to a different address.You know I am talking about in my notes I cramp lines together, not in the program? I don't want my notes as thick as a book.
 
Last edited:
  • #66
yungman said:
I know perfectly well Copy Constructor ONLY help with copying class object with pointers, that Copy Constructor will copy pointers that points to a different address.

That's not true.

There are other cases - suppose you have a member that is the time of creation of that object. It's the programmer's decision on whether he wants this time updated or not when the object takes on a new value. A custom copy constructor and/or a custom assignment operator would be the way to do this.
 
  • #67
yungman said:
//The copy constructor must be left from old notes, I understand perfectly clone = bob is assignment. I emphasis in my notes of the Rule of Three.
These are the notes that you updated several times. If you make notes, it's important to keep them up-to-date. Otherwise, you'll look at the notes again in a month or six months, and make the same mistake again.
yungman said:
You know I am talking about in my notes I cramp lines together, not in the program? I don't want my notes as thick as a book.
You pack lines together in the programs you show, as well. IMO, your notes are not as helpful as they could be, with all the code in bold and in lots of different colors. When you emphasize everything, then nothing stands out.
Your call -- you can have a thin set of notes that is almost unreadable, or you can space things out a bit, to make them readable and therefore useful, at the cost of a few more pages.

If you really want to squeeze stuff in, you could change the font size in Word to 4 points...
 
  • Like
Likes Vanadium 50
  • #68
Mark44 said:
You pack lines together in the programs you show, as well. IMO, your notes are not as helpful as they could be, with all the code in bold and in lots of different colors. When you emphasize everything, then nothing stands out.
Your call -- you can have a thin set of notes that is almost unreadable, or you can space things out a bit, to make them readable and therefore useful, at the cost of a few more pages.

If you really want to squeeze stuff in, you could change the font size to 4 points...
I can read my notes just fine, To be honest, I like program packed, I have more issue flipping pages to read a program than packing everything in one page. I can honor what you said if I post program here, I need to space it out so people can read better. But if I write program for myself to read, I still like to pack it for my reading. I will space it out before I post here, but I am still for packing.

Remember the notes are for me to read.
 
  • #69
yungman said:
Remember the notes are for me to read.
Not when you post them here. To be honest, the notes you posted in this thread are awful -- too packed, too much bold, too much color.
 
  • Like
Likes Vanadium 50
  • #70
Vanadium 50 said:
That's not true.

There are other cases - suppose you have a member that is the time of creation of that object. It's the programmer's decision on whether he wants this time updated or not when the object takes on a new value. A custom copy constructor and/or a custom assignment operator would be the way to do this.
Thanks

I am sure there are a lot more to this. So far, I only go by Gaddis book that emphasize on copying pointers but point to different addresses. Just have to learn as it comes. As good as Gaddis's book, it only cover one specific case for each topic, it doesn't cover all cases. I know from the get go that going through just the examples in the book is not even close to enough to learn. That's the reason I spent so much time working on c-string, passing around like in this thread and a few others. Gaddis mostly using int and float to pass around which is a LOT easier than c-string names and all that.
 
  • #71
I am reviewing math operators overloading. I have a question about math overloading operator xx (). Say I want to have a return of class object what is the difference between:
C++:
class Test;
Type A,B;
// operator xx where xx can be +, -, *, / etc.
Test& operator xx ( const Test &rhs){Test result; ...  ; return result;}//declare return type as reference.
Test operator xx ( const Test &rhs){Test result; ...  ; return result;}//declare return type is Test Object.

I actually tried both, seems like both return object result even though line 3 claims return type is a reference. I don't understand this. Can anyone elaborate this a little?

Thanks
 
  • #72
yungman said:
I am reviewing math operators overloading. I have a question about math overloading operator xx (). Say I want to have a return of class object what is the difference between:
C++:
class Test;
Type A,B;
// operator xx where xx can be +, -, *, / etc.
Test& operator xx ( const Test &rhs){Test result; ...  ; return result;}//declare return type as reference.
Test operator xx ( const Test &rhs){Test result; ...  ; return result;}//declare return type is Test Object.

I actually tried both, seems like both return object result even though line 3 claims return type is a reference. I don't understand this. Can anyone elaborate this a little?

Thanks
A reference is like a pointer. Under the hood, it only is the address you're returning. You don't want to return a reference to a destroyed object.
 
  • Like
Likes yungman
  • #73
Jarvis323 said:
A reference is like a pointer. Under the hood, it only is the address you're returning. You don't want to return a reference to a destroyed object.
Thanks for the reply, seems like the book always return a reference!
I think it is always used in the case:
C++:
Test C;
C = A + B;

result is going to be destroy right after it gets passed to C and is out of scope. I remember tracing programs and the result got destroy almost right away. So does it matter either case be it as reference or as object. This is part I'm still not clear.

Thanks
 
  • #74
result will be destroyed when it goes out of scope. That's at the end of the function at the }. So the returned reference will be invalid. So you need to return a value in that case.

You can return a member variable by reference because it still exists as part of the class instance.
 
  • Like
Likes yungman
  • #75
Jarvis323 said:
result will be destroyed when it goes out of scope. That's at the end of the function at the }. So the returned reference will be invalid. So you need to return a value in that case.

You can return a member variable by reference because it still exists as part of the class instance.
Thank you. I put it in my notes.
 
  • #76
I am still reading Copy Constructor and Assignment overloading operator. I want to confirm this:

C++:
class Test{};
Test A;
Test B = A;// Using Copy Constructor only because B is being created and copy A over.
Test C;
C = A;//This uses Assignment overload operator, NOT Copy Constructor as C already exist.

I put my comment in the program. I want to verify I am right.

Thanks
 
  • #77
The above is correct.
Code:
Test B = A; // calls copy constructor; equivalent to Test B(A);
Test C; C = A; // calls copy assignment operator
 
  • Like
Likes yungman
  • #78
jbunniii said:
The above is correct.
Code:
Test B = A; // calls copy constructor; equivalent to Test B(A);
Test C; C = A; // calls copy assignment operator
Thanks

I just want to make sure you said copy assignment operator, that is void operator=(const Test&rhs).
Of cause if I want to return something, it would be Test operator=(const Test&rhs)

Thanks
 
  • #79
yungman said:
Thanks

I just want to make sure you said copy assignment operator, that is void operator=(const Test&rhs).
Of cause if I want to return something, it would be Test operator=(const Test&rhs)

Thanks
A properly defined copy assignment operator must always return a non-const reference to *this. This is necessary in order for the usual assignment semantics to work, for example a = b = c; would result in a compilation error if your assignment operator doesn't return anything.

So the declaration should be Test& operator=(const Test& rhs);

The standard implementation is

Code:
Test& operator=(const Test& rhs)
{
    if (&rhs == this) {
        return *this;
    }
    // example assuming This has two member variables:
    //    int someInt;
    //    std::string someString;
    someInt = rhs.someInt;
    someString = rhs.someString;
    return *this;
}

Btw, I said copy assignment operator instead of just assignment operator, because there's also a move assignment operator, which you declare as Test& operator=(Test&& rhs);
 
  • Like
Likes yungman
  • #80
jbunniii said:
A properly defined copy assignment operator must always return a non-const reference to *this. This is necessary in order for the usual assignment semantics to work, for example a = b = c; would result in a compilation error if your assignment operator doesn't return anything.

So the declaration should be Test& operator=(const Test& rhs);

The standard implementation is

Code:
Test& operator=(const Test& rhs)
{
    if (&rhs == this) {
        return *this;
    }
    // example assuming This has two member variables:
    //    int someInt;
    //    std::string someString;
    someInt = rhs.someInt;
    someString = rhs.SomeString;
    return *this;
}

Btw, I said copy assignment operator instead of just assignment operator, because there's also a move assignment operator, which you declare as Test& operator=(Test&& rhs);

jbunniii said:
A properly defined copy assignment operator must always return a non-const reference to *this. This is necessary in order for the usual assignment semantics to work, for example a = b = c; would result in a compilation error if your assignment operator doesn't return anything.

So the declaration should be Test& operator=(const Test& rhs);

The standard implementation is

Code:
Test& operator=(const Test& rhs)
{
    if (&rhs == this) {
        return *this;
    }
    // example assuming This has two member variables:
    //    int someInt;
    //    std::string someString;
    someInt = rhs.someInt;
    someString = rhs.someString;
    return *this;
}

Btw, I said copy assignment operator instead of just assignment operator, because there's also a move assignment operator, which you declare as Test& operator=(Test&& rhs);
Thanks for the reply.

I was just talking about Test& operator=(const Test& rhs) vs Test operator=(const Test& rhs);
I thought I should use the second one to return the object instead of reference of the object as talked in post 72 onward. Which way is right?

Thanks
 
  • #81
yungman said:
Thanks for the reply.

I was just talking about Test& operator=(const Test& rhs) vs Test operator=(const Test& rhs);
I thought I should use the second one to return the object instead of reference of the object as talked in post 72 onward. Which way is right?

Thanks
The first one is right. The second one will also work if Test is copyable, but will result in unnecessary extra work.

Consider the assignment chain a = b = c;

If your assignment operator returns a reference (Test&), then the above chain will result in two calls to the assignment operator, as you would expect.

On the other hand, if your assignment operator returns a value (Test), then the above chain will result in two calls to the assignment operator, plus two calls to the copy constructor (in order to return temporary unnamed copies of b and a), plus two calls to the destructor (in order to destroy the temporary unnamed copies).
 
  • Like
Likes yungman
  • #82
Your example in post #72 is different. Copying it here for convenience:
Code:
Test& operator xx ( const Test &rhs){Test result; ...  ; return result;}//declare return type as reference.
Test operator xx ( const Test &rhs){Test result; ...  ; return result;}
Here, your operator xx is creating a local Test object and returning it. You have no choice but to return a copy (the second implementation). If you return a reference (the first implementation), then the object (result) to which that reference points will be destroyed before the caller can use it. This error is called a dangling reference.

But for the assignment operator, you're returning a reference to *this, which is not a local variable and still exists after the assignment operator exits. In particular, a correctly implemented assignment operator does not return a local variable (like your Test result; in the example above).

Your example above is more typical of binary operators that create a new object given two objects, such as operator+.
 
  • Like
Likes yungman
  • #83
jbunniii said:
Your example in post #72 is different. Copying it here for convenience:
Code:
Test& operator xx ( const Test &rhs){Test result; ...  ; return result;}//declare return type as reference.
Test operator xx ( const Test &rhs){Test result; ...  ; return result;}
Here, your operator xx is creating a local Test object and returning it. You have no choice but to return a copy (the second implementation). If you return a reference (the first implementation), then the object (result) to which that reference points will be destroyed before the caller can use it. This error is called a dangling reference.

But for the assignment operator, you're returning a reference to *this, which is not a local variable and still exists after the assignment operator exits. In particular, a correctly implemented assignment operator does not return a local variable (like your Test result; in the example above).

Your example above is more typical of binary operators that create a new object given two objects, such as operator+.
Thanks so much

I actually wrote a program for both cases to proof using Test&operator() doesn't work.
C++:
#include <iostream>
using namespace std;
const int Nsize = 51;
class Test1//Passing  as reference, not working.
{public:
    char* name;
    int x;
    Test1()
    {
        name = new char[Nsize];strncpy_s(name, Nsize, "blank", Nsize);
    }
    Test1(const char*desc, int x0)
    {
        name = new char[Nsize];strncpy_s(name, Nsize, desc, Nsize);x = x0;
    }
    Test1(const Test1& right)
    {
        name = new char[Nsize];strncpy_s(name, Nsize, right.name, Nsize);
        x = right.x;
    }
    Test1& operator = (const Test1&rhs)//Passing as reference
    {
        x = rhs.x; return *this;
    }
    Test1& operator+(const Test1& rhs)//Passing as reference
    {
        Test1 sum; sum.x = x + rhs.x; return sum;
    }
    void print()
    {
        cout << name << " = (" << name << ", " << x << ")\n\n";
    }
    ~Test1()
    {
        delete[] name;
    }
};
class Test2//Passing as Object, works.
{public:
    char* name;
    int x;
    Test2()//Constructor
    {
        name = new char[Nsize];    strncpy_s(name, Nsize, "blank", Nsize);
    }
    Test2(const char* desc, const int x0)//Constructor
    {
        name = new char[Nsize];    strncpy_s(name, Nsize, desc, Nsize);
        x = x0;  
    }
    Test2(const Test2& right)//Copy constructor
    {
        name = new char[Nsize];
        strncpy_s(name, Nsize, right.name, Nsize);
        x = right.x;
    }
    Test2 operator = (const Test2& rhs)
    {
        x = rhs.x;
        return *this;  
    }
    Test2 operator+(const Test2& rhs)
    {
        Test2 sum;
        sum.x = x + rhs.x;  
        return sum;
    }
    void print()
    {
        cout << name << " = (" << name << ", " << x << ")\n\n";
    }
    ~Test2()
    {
        delete[] name;
    }
};
int main()
{
    Test1 A("B", 0);
    Test1 B("B", 1);
    Test1 C("C", 2);
    A = B + C; 
    A.print();
    Test2 D("D", 0);
    Test2 E("E", 3);
    Test2 F("F", 4);
    D = E + F; 
    D.print();
}

I stepped through the program in debug and actually saw sum got destroy before copying over as it went out of scope and got garbage in class Test1.

Thanks
 
Last edited:
  • #84
To the others that said I should space the code out like the program above. I find it very hard to read. Just look at how long the program gets, I have to scroll up and down to read, it is so easy to lost track. I much much prefer to read program like this:
C++:
#include <iostream>
using namespace std;
const int Nsize = 51;
class Test1
{public: char* name; int x;
    Test1()    {name = new char[Nsize];strncpy_s(name, Nsize, "blank", Nsize);}
    Test1(const char*desc, int x0){name = new char[Nsize];strncpy_s(name, Nsize, desc, Nsize);x = x0;}
    Test1(const Test1& right){name = new char[Nsize];strncpy_s(name, Nsize, right.name, Nsize);    x = right.x;}
    Test1& operator = (const Test1&rhs){x = rhs.x; return *this;}
    Test1& operator+(const Test1& rhs){Test1 sum; sum.x = x + rhs.x; return sum;    }
    void print(){cout << name << " = (" << name << ", " << x << ")\n\n";}
    ~Test1(){delete[] name;    }
};
class Test2
{public: char* name; int x;
    Test2()//Constructor
    {    name = new char[Nsize];    strncpy_s(name, Nsize, "blank", Nsize);    }
    Test2(const char* desc, const int x0)//Constructor
    {name = new char[Nsize];    strncpy_s(name, Nsize, desc, Nsize);x = x0;    }
    Test2(const Test2& right)//Copy constructor
    {name = new char[Nsize];    strncpy_s(name, Nsize, right.name, Nsize);x = right.x;}
    Test2 operator = (const Test2& rhs){x = rhs.x;return *this;    }
    Test2 operator+(const Test2& rhs){    Test2 sum;    sum.x = x + rhs.x;    return sum;    }
    void print(){cout << name << " = (" << name << ", " << x << ")\n\n";}
    ~Test2(){delete[] name;    }
};
int main()
{ Test1 A("B", 0);    Test1 B("B", 1);Test1 C("C", 2);
    Test2 D("D", 0);Test2 E("E", 3);Test2 F("F", 4);
    A = B + C;    A.print();
    D = E + F;    D.print();
}

But if I ask question here, I will honor the request, to space them out before posting.
 
  • #85
yungman said:
Thanks so much

I actually wrote a program for both cases to proof using Test&operator() doesn't work.
C++:
#include <iostream>
using namespace std;
const int Nsize = 51;
class Test1//Passing  as reference, not working.
{public:
    char* name;
    int x;
    Test1()
    {
        name = new char[Nsize];strncpy_s(name, Nsize, "blank", Nsize);
    }
    Test1(const char*desc, int x0)
    {
        name = new char[Nsize];strncpy_s(name, Nsize, desc, Nsize);x = x0;
    }
    Test1(const Test1& right)
    {
        name = new char[Nsize];strncpy_s(name, Nsize, right.name, Nsize);
        x = right.x;
    }
    Test1& operator = (const Test1&rhs)//Passing as reference
    {
        x = rhs.x; return *this;
    }
    Test1& operator+(const Test1& rhs)//Passing as reference
    {
        Test1 sum; sum.x = x + rhs.x; return sum;
    }
    void print()
    {
        cout << name << " = (" << name << ", " << x << ")\n\n";
    }
    ~Test1()
    {
        delete[] name;
    }
};
class Test2//Passing as Object, works.
{public:
    char* name;
    int x;
    Test2()//Constructor
    {
        name = new char[Nsize];    strncpy_s(name, Nsize, "blank", Nsize);
    }
    Test2(const char* desc, const int x0)//Constructor
    {
        name = new char[Nsize];    strncpy_s(name, Nsize, desc, Nsize);
        x = x0; 
    }
    Test2(const Test2& right)//Copy constructor
    {
        name = new char[Nsize];
        strncpy_s(name, Nsize, right.name, Nsize);
        x = right.x;
    }
    Test2 operator = (const Test2& rhs)
    {
        x = rhs.x;
        return *this; 
    }
    Test2 operator+(const Test2& rhs)
    {
        Test2 sum;
        sum.x = x + rhs.x; 
        return sum;
    }
    void print()
    {
        cout << name << " = (" << name << ", " << x << ")\n\n";
    }
    ~Test2()
    {
        delete[] name;
    }
};
int main()
{
    Test1 A("B", 0);
    Test1 B("B", 1);
    Test1 C("C", 2);
    A = B + C;
    A.print();
    Test2 D("D", 0);
    Test2 E("E", 3);
    Test2 F("F", 4);
    D = E + F;
    D.print();
}

I stepped through the program in debug and actually saw sum got destroy before copying over as it went out of scope and got garbage in class Test1.

Thanks
On an unrelated note, I noticed that your no-argument constructors (Test1() and Test2()) are failing to initialize the member variable x, and since you don't have a default initializer for x, it will be uninitialized, hence will probably contain garbage. In general it's a very good practice to provide a default initializer for any member variable that is of a type (such as int) that would otherwise be uninitialized. Example:
Code:
class Test1//Passing  as reference, not working.

{public:

    char* name = ""; // default initialization
    int x = 0; // default initialization

    Test1()
    {
        name = new char[Nsize];
        strncpy_s(name, Nsize, "blank", Nsize);
        // x will have the default-initialized value of zero since
        // this constructor doesn't assign a value to x
    }

    Test1(const char*desc, int x0)
    {
        name = new char[Nsize];
        strncpy_s(name, Nsize, desc, Nsize);
        x = x0;
    }
 
  • #86
yungman said:
To the others that said I should space the code out like the program above. I find it very hard to read. Just look at how long the program gets, I have to scroll up and down to read, it is so easy to lost track. I much much prefer to read program like this:

...

But if I ask question here, I will honor the request, to space them out before posting.
It's up to you how to format code that only you will read, but it's definitely a good practice to use a reasonably standard code style (one statement per line, use whitespace to improve readability, etc.) for any code that others will read. That includes this forum, but also and more importantly any code that will be read or maintained by others, e.g. in an open-source project or for an employer or customer.

For a good example of the style generally used by professional C++ developers, you can take a look at Google's C++ style guide: https://google.github.io/styleguide/cppguide.html
 
  • #87
One more thing I just noticed, your operator= is only assigning x, not name.
Code:
    Test1& operator = (const Test1&rhs)//Passing as reference
    {
        x = rhs.x;
        return *this;
    }
This is not illegal, but it will certainly result in unexpected behavior, e.g.:
Code:
Test1 t1("a", 1);
Test2 t2("b", 2);

// One would reasonably expect the following to result in
//   t1.name = "b"  and  t1.x = 2
// but instead it will result in
//   t1.name = "a"  and  t1.x = 2
t1 = t2;
A more natural implementation would be
Code:
    Test1& operator=(const Test1& rhs)
    {
        if (&rhs != this) {
            x = rhs.x;
            strncpy_s(name, Nsize, rhs.name, Nsize);
        }
        return *this;
    }
 
  • Like
Likes yungman
  • #88
yungman said:
To the others that said I should space the code out like the program above. I find it very hard to read. Just look at how long the program gets, I have to scroll up and down to read, it is so easy to lost track.
It's worse when you pack two or three statements on a line -- it's easy to miss them. Plus, the debugger can't stop at one of those individual statements.
yungman said:
I much much prefer to read program like this:
You're pretty much alone in this. Most of us who have been doing this for years really dislike the packed format that you favor -- it's really easy to miss something important.
jbunniii said:
t's up to you how to format code that only you will read, but it's definitely a good practice to use a reasonably standard code style (one statement per line, use whitespace to improve readability, etc.) for any code that others will read.
I agree 100%. If it's code that only @yungman will read, then whatever floats his boat is fine. But if he posts it here, please do the rest of us a favor and space it out. We don't mind scrolling down through the code.
 
  • Like
Likes jbunniii and Vanadium 50
  • #89
Mark44 said:
It's worse when you pack two or three statements on a line -- it's easy to miss them. Plus, the debugger can't stop at one of those individual statements.
You're pretty much alone in this. Most of us who have been doing this for years really dislike the packed format that you favor -- it's really easy to miss something important.
I agree 100%. If it's code that only @yungman will read, then whatever floats his boat is fine. But if he posts it here, please do the rest of us a favor and space it out. We don't mind scrolling down through the code.
That's what I said, I post with the code spaced out like in post 83. I just said for me, I rather read packed code. It doesn't matter to anyone if I space them out before I post. I can honor that. In my notes, I like different color in my own notes, because I can find the name in other part of the program easier and also not drop out from one line to the other.
jbunniii said:
One more thing I just noticed, your operator= is only assigning x, not name.
Code:
    Test1& operator = (const Test1&rhs)//Passing as reference
    {
        x = rhs.x;
        return *this;
    }
This is not illegal, but it will certainly result in unexpected behavior, e.g.:
Code:
Test1 t1("a", 1);
Test2 t2("b", 2);

// One would reasonably expect the following to result in
//   t1.name = "b"  and  t1.x = 2
// but instead it will result in
//   t1.name = "a"  and  t1.x = 2
t1 = t2;
A more natural implementation would be
Code:
    Test1& operator=(const Test1& rhs)
    {
        if (&rhs != this) {
            x = rhs.x;
            strncpy_s(name, Nsize, rhs.name, Nsize);
        }
        return *this;
    }
Yes, actually I did that already, I originally had the name copied over in the Copy Constructor. Actually dealing with the name is the main reason I created this thread. Here I want to keep the name in A and D as 'A' and 'D' resp., so I decided to removed
C++:
strncpy_s(name, Nsize, rhs, Nsize)
and leave the original name alone in A and D. It is intentional on my part.

Thanks
 
  • #90
Mark44 said:
It's worse when you pack two or three statements on a line -- it's easy to miss them. Plus, the debugger can't stop at one of those individual statements.
You're pretty much alone in this. Most of us who have been doing this for years really dislike the packed format that you favor -- it's really easy to miss something important.
I agree 100%. If it's code that only @yungman will read, then whatever floats his boat is fine. But if he posts it here, please do the rest of us a favor and space it out. We don't mind scrolling down through the code.
Like I said, I will space the code out like in post #73. I just commented I find it easier to read when putting all the lines together so I don't have to scroll up and down. To each their own, I will honor the forum here and space it out.
 
Back
Top