0

I have a problem with Overloading operator 'new' in my class.

Code:

time.h

#ifndef TIME_H_
#define TIME_H_

#include <cstddef>
#include <stdlib.h>

class Time {
private:
    int hours;
    int minutes;

public:
    Time(int a = 0, int b = 0) : hours(a), minutes(b) {};

    void AddMin(int m);
    void AddHours(int h);
    void Reset(int h = 0, int m = 0);
    void Show() const;

    Time Suma(const Time & t) const;


    //przeladowania
    void* operator new(size_t);

};
#endif

time.cpp

 #include "time.h"
#include <iostream>
#include <cstddef>
#include <stdlib.h>

void Time::AddMin(int m)
{
    this->minutes += m;
    this->hours += this->minutes / 60;
    this->minutes += this->minutes % 60;
}

void Time::AddHours(int h)
{
    this->hours += h;
}

void Time::Reset(int h, int m)
{
    this->hours = h;
    this->minutes = m;
}

void Time::Show() const
{
    std::cout << this->hours << " hours and " << this->minutes << " minutes" << std::endl;
}

////overloading
void* Time::operator new(size_t size)
{
    void *storage = malloc(size);
    if (NULL == storage) {
        throw "allocation fail : no free memory";
    }
    std::cout << storage << std::endl;
    Time * time = (Time*)storage;
    time->minutes = 12;

    return time;
}

prog.cpp

#include <iostream>
#include "time.h"

int main()
{
    Time * timeNew = new Time();
    timeNew->Show();
    std::cout << timeNew << std::endl;

    return 0;
}

And results - addreses:

0104F5E8
0 hours and 0 minutes
0104F5E8

I don't understand why my objects have other adresses in memory. I think if I return pointer, so my object timeNew(in prog.cpp) should have the same adress as storage in time.cpp.

I konw it's a function, but I used pointer, so it shouldn't delete after return to program.

Why timeNew has 0 hours and 0 minutes? I sign value in function.

Could you explain me what I do wrong?

diego9403
  • 13
  • 4
  • 2
    `&timeNew` is the address of the **pointer**, not the **pointee**! Overloading allocation is a fairly advanced topic. [You should grab a good book to get a handle on the basics first](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – StoryTeller - Unslander Monica Sep 14 '17 at 08:54
  • Ok. I see. But, when I sign some value in operator function(I will edit my post) timeNew is zero. Why? I can't sign something in new. I know it has no sens, but I would like to know. – diego9403 Sep 14 '17 at 09:01
  • 1
    Seriously, go over the suggested reading material. There are too many basic principles you aren't aware off. I'm not trying to belittle you, but C++ is not a language to be learned by trial and error. You need the basics first. Then you'd know that `operator new` only allocates **storage**, and the object construction happens as the second step. – StoryTeller - Unslander Monica Sep 14 '17 at 09:08
  • The `()` in `new Time();` will initialize the object *after* returning from your `operator new`. The order is: first allocate memory, then call the constructor. – Bo Persson Sep 14 '17 at 09:12
  • Thank you. I deleted my constructor and wrote empty one(to bypass default constructor) and now works. I am reading now C++ Primer Plus Stephen Prata. – diego9403 Sep 14 '17 at 09:17

1 Answers1

-1

Note: as StoryTeller pointed out in the comments, accessing an object before the constructor was called is generally a very bad practice and potentially prone to dangerous bugs. It's also almost never necessary. Unless you are knowingly implementing a dirty hack, you should probably not do this. Keep in mind that the new operator in c++ is absolutely different from what you might find in python for instance, where it's used to created immutable types.

Why timeNew has 0 hours and 0 minutes? I assign a value in the new function.

This happens because after the operator new, the constructor is called and since you pass no argument, the constructor will reset the values for minute and hours after you assigned 12 to minutes.

If you want to see the effect of this assignment in operator new, simply change:

 Time(int a = 0, int b = 0) : hours(a), minutes(b) {};

with:

 Time(int a, int b) : hours(a), minutes(b) {};
 Time() {};
Flynsee
  • 596
  • 4
  • 17
  • You **really really really* shouldn't treat raw storage as an object. – StoryTeller - Unslander Monica Sep 14 '17 at 09:18
  • @StoryTeller This is just for the sake of explaining my thoughts and I know it's not a good coding practice but why is it dangerous? – Flynsee Sep 14 '17 at 09:22
  • The object need not be POD. Suggesting it's okay may inadvertently encourage readers of this answer to call member functions. The more complex the type will become, the more likely this will cause calamity. Better to do as the standard specifies. Until the c'tor runs, there is no object there, only storage. – StoryTeller - Unslander Monica Sep 14 '17 at 09:26
  • @StoryTeller Oh I see, you mean what OP does in the new operator is really bad? Indeed, I agree there. I thought you were referring to what I wrote in my answer. – Flynsee Sep 14 '17 at 09:29
  • Yes, I was referring to what the OP did. What worries me is that allowing the OP to "see" the change may encourage them to keep doing what they are doing. – StoryTeller - Unslander Monica Sep 14 '17 at 09:32
  • Let's hope they're using this for a specific corner case in their code that requires a dirty hack, rather than because they're reproducing something they saw in python – Flynsee Sep 14 '17 at 09:35
  • 2
    Just to add: Two good reasons for not doing it is that operator new can be inherited so the yet-to-be-constructed object isn't necessarily "class Time", and this new isn't called if a Time-object is a member of a class that is dynamically allocated - thus skipping the initialization. – Hans Olsson Sep 14 '17 at 09:55
  • This answer demonstrates a way it should NOT be done. Converting result of `operator new()` to a `Time *` results in a pointer to an object that has not been constructed. The assignment `*timeNew = Time(2,30)` then changes that object. Using an object before it has been properly constructed gives undefined behaviour even if, sometimes, you'll get lucky and it seems to work. – Peter Sep 14 '17 at 10:15
  • @Peter Again, this is just for the sake of explaining what the compiler does. gcc compiles it exactly the same as a `new Time()` by the way. I'll remove the last part I guess, it's not essential to the answer anyway, but I thought it added some clarity. – Flynsee Sep 14 '17 at 10:21