473,406 Members | 2,387 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

Returning an object that contains a pointer to data

3
Hello all!

I have a class like this:
Expand|Select|Wrap|Line Numbers
  1. class MyClass
  2. {
  3. public:
  4.     MyClass(int Count)
  5.     {
  6.         Data = new double[Count];
  7.     };
  8.  
  9.     ~MyClass()
  10.     {
  11.         delete [] Data;
  12.     }
  13.  
  14.     // Some methods to set/get the Data, modify the data,
  15.     // a complete set of overloaded operators, etc.
  16.  
  17.     const MyClass operator + (const MyClass &Target) const
  18.     {
  19.         MyClass Temp(Count);
  20.         Temp = *this;
  21.  
  22.         // The addition algorithm is here...
  23.  
  24.         return Temp;
  25.     }
  26.  
  27. private:
  28.     double *Data;
  29. };
  30.  
Of course, something like this
Expand|Select|Wrap|Line Numbers
  1. MyClass obj1(4), obj2(4), obj3(4);
  2. obj3 = obj1 + obj2;// Can't do this!
  3.  
will cause a crash because the Temp::Data is freed when operator+ returns and the assignment operator then tries to access Data (yeah, I didn't show it, but it does).

For a short time, I added a boolean class member called DeleteElements, and changed the destructor to this:
Expand|Select|Wrap|Line Numbers
  1.     ~MyClass()
  2.     {
  3.         if (DeleteElements)
  4.             delete [] Data;
  5.     }
  6.  
and I change the operators to something like this
Expand|Select|Wrap|Line Numbers
  1.     MyClass operator + (MyClass &Target) const
  2.     {
  3.         MyClass Temp(Count);
  4.         Temp = *this;
  5.  
  6.         // The addition algorithm is here...
  7.  
  8.         Temp.DeleteElements = false;
  9.  
  10.         return Temp;
  11.     }
  12.  
and then you need to very carefully manage the DeleteElements flag to avoid memory leaks. Obviously, this is undesirable (but it works). Besides these reasons, I want to avoid using this method because I cannot use the correct versions of the overloaded operator function signatures (with the consts).

Has anyone else run into these problems? Is there an elegant solution? I'd like to avoid completely re-writing the class, but I can if that's the most effective way to handle the problem.

Thanks for the help!

-Kerry
Jun 17 '09 #1
6 1973
newb16
687 512MB
Looks like shared pointer (shared_ptr).
the correct versions of the overloaded operator function signatures (with the consts).
There is mutable keyword and const_cast.
Jun 17 '09 #2
Banfa
9,065 Expert Mod 8TB
Because you have not defined a copy constructor or an operator= for your class the compiler creates them for you. However the compiler creates a shallow copy algorithm, this just copies the members of the source object to the destination object and both objects end up pointing to the same memory block.

You need a deep copy, a deep copy rather than copy the members directly is intelligent enough to allocate a new buffer for the destination object and copy the data pointed to rather than the pointer. You have to implement these yourself by implementing a copy constructor and a operator= but you would not need to modify any existing members of the class.


However at least 2 other methods to solve the problem occur to me. Your class basically holds an array of doubles of variable size and allows one array to be added to another. Rather than the method above you use you could
  1. Use a template class. The template parameter would be the size of the array. You would not need to new or delete any data so a shallow copy would work

    Expand|Select|Wrap|Line Numbers
    1. template<int SIZE>
    2. class MyClass
    3. {
    4. ...
    5.  
    6. private: 
    7.     double Data[SIZE];
    8. }
    9.  
    If you needed to you could add a helper function to add classes with different sized arrays and if you didn't need to the compiler would raise an error if you tried. The size of the array becomes part of the class definition rather than a parameter of the class. This would prevent easy resizing of the array though.
  2. The second option is use a vector. If you ever find yourself using an array or using a pointer and new to dynamically create an array then you should be asking yourself "Why am I not using a vector?" If you have no good reason then you should use a vector. If you used a vector in place of your pointer in the class as is it would work because a vector knows how to copy itself and a shallow copy of your class would work.

The main point is you are trying to do a lot of work manually that the STL or the compiler will do for you and that is always a mistake.
Jun 17 '09 #3
KLoux
3
Banfa, thanks for the info.

Just for my own knowledge - what (in your opinion?) would be a "good reason" for not using a std::vector instead of an array?

And you are right about my not having defined a copy constructor, but I did define an assignment operator that performs a deep copy (it's just not shown). I'm not clear on whether or not adding a copy constructor that performs a deep copy would fix my problem... would the copy constructor be called in the following statement?
Expand|Select|Wrap|Line Numbers
  1. MyClass obj1, obj2, obj3;
  2. obj1 = obj2 + obj3;
  3.  
This should be the same as (I think)
Expand|Select|Wrap|Line Numbers
  1. obj1.operator=(obj2.operator+(obj3));
  2.  
... no copy constructor. And the memory is lost when operator+ returns before operator= is even called, so the fact that operator= does a deep copy doesn't matter, as the leak has already occured. Am I wrong?

I've considered using a template, but I'm not sure that will work for me either. What I'm really doing is writing a simple matrix algebra class (I know it's been done, but I wanted to give it a shot myself). My goal was to allow for arbitrarily sized matricies (which a template would do), but say I had something like this:
Expand|Select|Wrap|Line Numbers
  1. Matrix<4, 3> fourByThreeMatrix;
  2. Matrix<3, 5> threeByFiveMatrix;
  3. Matrix<4, 5> fourByFiveMatrix = fourByThreeMatrix * threeByFiveMatrix;
  4.  
Would it work? I'm not sure I could overload operators to handle multiplication by other arbitrarily sized matricies.

It sounds like the std::vector approach is the best way for me to go.

Thanks again for the help!

-Kerry
Jun 17 '09 #4
Banfa
9,065 Expert Mod 8TB
@KLoux
Off the top of my head in a purely C++ program I can't think of a standard generic reason, it would have to be extremely situation specific. If you had to interface to some legacy C code there is more likely to be an instance of needing to use a pointer or array (but note that for single dimensioned arrays vectors maintain the same memory map).

@KLoux
Your code is right but there is an omission in your understanding of what this code does.

Your operator+ returns an object (a temporary one that is on the stack). In order to do this the compile constructs an invisible temporary object from the return value which is guaranteed to still exist after the function call has returned (your temp variable is guaranteed not to exist at this point). This temporary object is then used by the calling code to access the return value The copy constructor is called while creating this hidden temporary object implicit in the return from operator+ causing your error.

This is one of the places where C++ is poor in my opinion. It is too easy to make the mistake you have made and not obvious what the cause is (until you know of course).


As to you matrix class you may not be able to write class member functions for things like multiplication but you may be able to write a helper function to do it. A helper function is a normal function made to operate with a class without actually being a part of the class for instance this

Expand|Select|Wrap|Line Numbers
  1. matrix<int N, int M> operator*(matrix<int N, int Q>m1, matrix<int Q, int M>m2)
  2. {
  3.     ...
  4. }
  5.  
might be possible, and if it is would enforce the correct input and output parameter types.

Note I say might, I am not actually sure on this point.

Otherwise vectors rather than pointers and dynamic arrays is a much better idea.
Jun 17 '09 #5
KLoux
3
Great, thanks for the info - This is a big help!

-Kerry
Jun 17 '09 #6
Banfa
9,065 Expert Mod 8TB
I should have said in my previous post that having a copy constructor and operator= normally goes hand in hand. If you need one then usually you need the other.
Jun 17 '09 #7

Sign in to post your reply or Sign up for a free account.

Similar topics

7
by: Pablo J Royo | last post by:
Hello: i have a function that reads a file as an argument and returns a reference to an object that contains some information obtained from the file: FData &ReadFile(string FilePath); But ,...
5
by: Gent | last post by:
I have two questions which are very similar: Is it possible to return an object in C++. Below is part of my code for reference however I am more concerned about the concept. It seems like the...
25
by: Victor Bazarov | last post by:
In the project I'm maintaining I've seen two distinct techniques used for returning an object from a function. One is AType function(AType const& arg) { AType retval(arg); // or default...
11
by: Justin Naidl | last post by:
class Foo { protected: char foo_stuff; public: char* get_foo_stuff(); } Given the above example. What I want to know is the "proper/standard" way
9
by: CptDondo | last post by:
I am working on an embedded platform which has a block of battery-backed RAM. I need to store various types of data in this block of memory - for example, bitmapped data for control registers,...
17
by: I.M. !Knuth | last post by:
Hi. I'm more-or-less a C newbie. I thought I had pointers under control until I started goofing around with this: ...
7
by: Arpan | last post by:
The .NET Framework 2.0 documentation states that An Object variable always holds a pointer to the data, never the data itself. Now w.r.t. the following ASP.NET code snippet, can someone please...
23
by: pauldepstein | last post by:
Below is posted from a link for Stanford students in computer science. QUOTE BEGINS HERE Because of the risk of misuse, some experts recommend never returning a reference from a function or...
275
by: Astley Le Jasper | last post by:
Sorry for the numpty question ... How do you find the reference name of an object? So if i have this bob = modulename.objectname() how do i find that the name is 'bob'
5
by: ctj951 | last post by:
I have a very specific question about a language issue that I was hoping to get an answer to. If you allocate a structure that contains an array as a local variable inside a function and return...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.