Someone knows why the Latter syntax for calling , Dog::operator new is calling the default constructor after doing the allocation, ending up calling 2 constructors ?
I want to know if I'm doing something wrong, and how can I do:
Dog *ptr = new("arg") Dog();
without calling 2 constructors. and without using any trick, like checking in the default constructor if the object is already constructed. Here is the code:
class Dog
{
public:
Dog() // default
{
std::cout << "default Dog constructor [" << this << "]" << std::endl;
}
Dog(int x) // int argument
{
std::cout << "dog constructor int " << x << "[" << this << "]" << std::endl;
}
Dog(const std::string& word) // std::string argument
{
std::cout << "dog constructor std::string: " << word << " ["<< this << "]" << std::endl;
}
Dog(std::string &&word) // rvalue string argument
{
std::cout << "dog constructor std::string&& rvalue: " << word << " [" << this << "]" << std::endl;
}
// custom operator new
static void *operator new(std::size_t size) noexcept // for default constructor
{
Dog *ptr = (Dog*)malloc(size); // allocate memory
if (ptr) // if allocate ok
{
::new(ptr) Dog(); // call default constructor on object in memory
return ptr; // returns
}
else
return nullptr;
}
template<class T>
static void * operator new(std::size_t size, T&& value) noexcept // for argument constructor
{
Dog *ptr = (Dog*) malloc(size); // allocate the memory
if (ptr)
{
::new (ptr) Dog(std::forward<T>(value)); // pass the argument exactly as was passed to operator new,
// using perfect forwarding
return ptr;
}
else
return nullptr;
}
~Dog() { std::cout << "destructor " << std::endl; }
};
int main(void)
{
Dog *d = (Dog*) Dog::operator new(sizeof(Dog), "Const Char * Argument"); // argument version
Dog *d2 = (Dog*)Dog::operator new(sizeof(Dog)); // default constructor argument
//1 this works as expected, do what you specified in the member operator new, everything goes normal.
Dog *d3 = new Dog(); // default constructor
Dog *d4 = new("Const Char * Argument") Dog(); // argument constructor
// this is shorter, goes into your member operator new, BUT when it returns to this scope,
// call the default constructor for *d3, and for *d4 too.
// so this ends up calling constructors twice for both objects.
}
So, I was mixing allocation with construction, there's no reason for doing that here, maybe there is some use for that in operator new[] to construct the array with a contructor other than the default contructor.
But the the best way to define these members operators are:
class Dog {
public:
// .......
// custom operator new
static void *operator new(std::size_t size) noexcept // for default constructor
{
void *memory = malloc(size); // allocate memory
if (memory) // if allocate ok
{
return memory; // returns
}
else
return nullptr;
}
static void *operator new[](std::size_t size) noexcept
{
void *memory = malloc(size); // allocate memory
if (memory) // if allocate ok
{
return memory; // returns
}
else
return nullptr;
}
static void operator delete(void *block) noexcept
{
free(block);
}
static void operator delete[](void *block) noexcept
{
free(block);
}
~Dog() { std::cout << "destructor " << std::endl; }
};
int main(void)
{
// now we can use new operator normaly without complications
Dog *d1 = new Dog[10]; // default constructor on all objects
Dog *d2 = new Dog("const char * argument"); // call std::string&& constructor
delete[] d1;
delete d2;
}
Using (keyword) new: It invokes the allocating operator new and (!) calls the constructor.
Note: When providing an operator new you should provide an operator delete, too (in your case it would call free). Also, do not forget the array versions.
Related
I created ABC class and created its three objects by normal, assign and copy constructor. Now they are use same memory address for ptr.
When these objects are deleted means coming out of scope then first object deleted, but for second it is give error that memory is already deleted.
This is fine. that I understand.
#include<iostream>
using namespace std;
class ABC
{
private:
int a;
int *ptr;
public:
ABC(); // Simple constructor.
ABC(int a, int b); // Parameterized constructor.
ABC(const ABC &obj); // Copy constructor.
~ABC(); // Destructor.
void display(); // Display.
ABC& operator=(const ABC &obj); // Operator Overload.
};
ABC::ABC()
{
}
ABC::ABC(int a, int b)
{
cout << "Parameterized constructor" << endl;
// allocate memory for the pointer;
this->a = a;
ptr = new int;
ptr = &b;
}
ABC::ABC(const ABC &obj)
{
cout << "Copy constructor" << endl;
a = obj.a;
//ptr = new int;
//*ptr = *obj.ptr; // copy the value
ptr = obj.ptr;
}
ABC& ABC :: operator=(const ABC &obj)
{
cout <<"Assignemnt operator overload"<<endl;
this->a = obj.a;
this->ptr = obj.ptr;
return *this;
}
ABC::~ABC(void)
{
cout << "Freeing memory!" << endl;
delete ptr;
}
void ABC::display() {
cout << "a value = : " << a <<endl;
cout << "ptr value = : " << ptr <<endl;
cout << "*ptr value = : " << *ptr <<endl;
}
int main()
{
// Normal.
ABC obj1(1, 2);
cout << "Point Obj1 value = : "<<endl;
obj1.display();
cout<<"\n\n";
// Assignment.
ABC obj2;
obj2 = obj1;
cout << "Point Obj2 value = : "<<endl;
obj2.display();
cout<<"\n\n";
// Copy constructor.
ABC obj3(obj1);
cout << "Point Obj3 value = : "<<endl;
obj3.display();
return 0;
}
What I want to do it that, I do not want to delete memory when other objects are using. How to handle this by Smart Pointer, I not want to do by in-build sheared pointer. I want to write Smart Pointer class and increase ptr reference count when other objects use same memory. But do not know how to do.
class SmartPointer
{
public:
int *ptr;
int ref;
SmartPointer();
SmartPointer(int *p);
int& operator *();
~SmartPointer();
};
SmartPointer::SmartPointer()
{
cout<<"SmartPointerInitilaize default"<<endl;
ref = 1;
}
SmartPointer::SmartPointer(int *p)
{
cout<<"SmartPointerInitilaize para"<<endl;
ptr = p;
ref = 1;
}
int& SmartPointer:: operator *()
{
return *ptr;
}
SmartPointer::~SmartPointer()
{
cout<<"SmartPointer De-Initilaize"<<endl;
//delete ptr;
}
What you basically want to do is to implement a std::shared_ptr. You shouldn't do it normally, because it is quite tricky, however for educational purposes and to understand how that works:
1) The ref count needs to be part of the pointer data passed around (if not static), shared by all the "linked" SmartPointer instances.
2) You still need to define the copy constructor/assignment operator to increase the reference count. And in the destructor you decrease the refcount, and if zero, delete the pointer (and the extra data).
An example:
class SmartPointer
{
struct Data {
Data(int *p)
: ptr(p)
, ref(1)
{}
~Data() {Release();}
void Acquire() {
++ref;
}
void Release() {
if (!--ref) { delete ptr; delete this; }
}
int *ptr;
int ref;
};
Data *data;
public:
SmartPointer()
: data(new Data(NULL))
{}
SmartPointer(int *p)
: data(new Data(p))
{}
SmartPointer(const SmartPointer& x)
: data(x.data)
{ data->Acquire(); }
SmartPointer& operator =(const SmartPointer& x)
{
if (this != &x) {
data->Release();
data = x.data;
data->Acquire();
}
}
int& operator *() { return *data->ptr; }
~SmartPointer() { data->Release(); }
};
Note that this is very simplified (e.g. not thread safe), just the basic idea.
The actual std or boost shared_ptr is much more complicated (templated, supports custom deleter which involves type erasure etc.).
Add shared_level integer in SmartPointer
class SmartPointer{
public:
int *ptr;
int ref;
int shared_level;
SmartPointer();
SmartPointer(int *p);
int& operator *();
~SmartPointer();
};
Whenever the abc constructor is calling. Increment shared_level by 1. When ever deconstructor calls, Decrement it by 1.
And While deconstructing check for SmartPointer->shared_level value, And if it is 1. Delete pointer, else just decrements is enough.
Note : Better use locks for sharePointer, If u want to access in multiple threads.
I have read this link about new and delete in C++. There is a code that implemented Singleton pattern. I have tested this code:
#include <iostream>
#include <memory>
class Singleton {
static Singleton *instance;
static std::size_t refcount;
std::string _s;
public:
void setS(std::string s) { _s = s; }
std::string getS() { return _s; }
static void *operator new(std::size_t nbytes) throw (std::bad_alloc) {
std::cout << "operator new" << std::endl;
if (instance == nullptr) {
std::cout << "operator new nullptr" << std::endl;
instance = ::new Singleton; // Use the default allocator
}
refcount++;
return instance;
}
static void operator delete(void *p) {
std::cout << "operator delete" << std::endl;
if (--refcount == 0) {
std::cout << "operator delete" << refcount << std::endl;
::delete instance;
instance = nullptr;
}
}
};
Singleton *Singleton::instance = nullptr;
std::size_t Singleton::refcount = 0;
int main() {
Singleton* s = new Singleton;
//Singleton* t = new Singleton;
s->setS("string s");
std::cout << "s " << s->getS() << std::endl;
Singleton* t = new Singleton;
std::cout << "t " << t->getS() << std::endl;
return 0;
}
But the result is:
operator new
operator new nullptr
s string s
operator new
t
Why t didn't print out "string s"? If I change the comment line, t can print out "string s".
The statement new Singleton will call operator new to aquire storage, and then intialize the non-static members of the object using the default constructor.
As _s is not static, it will be (re)initialized every time a new Singleton is created. So will result in a blank string for t.
It is very likely UB to reuse the space for the _s member this way.
Is it possible to force std::make_shared to use a class's new operator? This relates to another SO question. According to that question, std::make_shared uses a custom allocator:
From the standard (ยง20.7.2.2.6 shared_ptr creation ):
Effects: Allocates memory suitable for an object of type T and constructs an object in that memory via the placement new expression
::new (pv) T(std::forward(args)...).
As such, I thought that I could use a custom placement new operator, but that appears to be false
// std::cout
#include <iostream>
// std::make_shared
#include <memory>
// Track what we're making
struct Foo {
Foo() {
std::cout << "Foo constructor" << std::endl;
}
Foo(Foo const & foo) {
std::cout << "Foo copy constructor" << std::endl;
}
Foo(Foo && foo) {
std::cout << "Foo move constructor" << std::endl;
}
Foo & operator = (Foo const & foo) {
std::cout << "Foo copy assignment" << std::endl;
return *this;
}
Foo & operator = (Foo && foo) {
std::cout << "Foo move assignment" << std::endl;
return *this;
}
void * operator new(std::size_t size) throw(std::bad_alloc) {
std::cout << "Foo new" << std::endl;
return ::operator new(size);
}
void * operator new(std::size_t size, void * p) throw() {
std::cout << "Foo placement new" << std::endl;
return ::operator new(size,p);
}
void* operator new (std::size_t size, std::nothrow_t const & nothrow_value)
throw()
{
std::cout << "Foo nonthrowing new" << std::endl;
return ::operator new(size,nothrow_value);
}
void operator delete(void * p, std::size_t size) {
std::cout << "Foo delete" << std::endl;
::operator delete(p);
}
~Foo() {
std::cout << "Foo destructor" << std::endl;
}
};
int main() {
std::cout << "---Creating foo" << std::endl;
auto foo = std::make_shared <Foo> ();
std::cout << "---Creating foo2" << std::endl;
auto foo2 = std::shared_ptr <Foo> (new Foo());
std::cout << "---Creating foo3" << std::endl;
auto foo3 = std::allocate_shared <Foo> (std::allocator <Foo>());
std::cout << "---fin" << std::endl;
}
which gives
---Creating foo
Foo constructor
---Creating foo2
Foo new
Foo constructor
---Creating foo3
Foo constructor
---fin
Foo destructor
Foo destructor
Foo delete
Foo destructor
Also tucked in there was an attempt to force an allocator that would call the custom new operator with the call to std::allocate_shared. In any case, is there a way to make std::make_shared call the custom new operators without defining a whole new allocator?
No, this is not possible (with make_shared).
Since a custom allocator for class T will typically be written and optimized (for example with a pool) to expect allocations of size T, and make_shared will be allocating more memory than that, I imagine it wasn't deemed an important feature to support.
Further, the standard provides allocate_shared for the case where you wish to use a custom allocator.
Sort of.
What you do instead is create a structure containing aligned storage with a custom destroyer that cleans up the object and a bool saying if you should do so.
Then placement new the aligned storage.
Now use the aliasing shared ptr constructor to return a pointer to the aligned storage as a different type.
In the code below is implemented a smart pointer that executes fine, but at the end I get the following message:
Here is the code:
smart_ptr.h:
#ifndef SMART_PTR_H
#define SMART_PTR_H
/*
Class: Auto_ptr
It implements a generic
smart pointer that doesn't need
to be deleted explicitly, i.e.
it provides garbage collection.
*/
template<class T>
class Auto_ptr{
public:
// constructors
explicit Auto_ptr(T* p = nullptr): value(p) { }; // constructor
Auto_ptr(Auto_ptr& p); // copy constructor
Auto_ptr& operator= (const Auto_ptr& p); // copy assignment
~Auto_ptr() { std::cout << "pointer deleted\n"; delete value; } // destructor
// access operators
const T& operator* () const { return *value; } // dereference operator
const T* operator->() const { return value; } // indirect class member access (arrow) operator
// non-modifying members
T* get() { return value; } // getter method
void reset(T* v); // reassing new value(default value: nullptr)
T* release(); // transfers the object to another pointer; without destroying it
private:
// data member
T* value;
};
//--------------------------------------------------------------------------------------------------------
// class Auto_ptr member implementations
// Constructors
// copy constructor
template<class T>
Auto_ptr<T>::Auto_ptr(Auto_ptr& p) {
value = p.release();
}
// copy assignment
template<class T>
Auto_ptr<T>& Auto_ptr<T>::operator= (const Auto_ptr& p ) {
if (this == &p) return *this;
if (value) delete value;
value = p.value;
return *this;
}
/*
Function: release()
Use: T ptr = auto_ptr_obj.release();
It transfers the pointer value to the
caller, setting the data member value
to nullptr.
*/
template <class T>
T* Auto_ptr<T>::release() {
T* temp = value;
value = nullptr;
return temp;
}
/*
Function: reset()
Use: auto_ptr_obj.release(new_pointer);
It deletes the object pointer to by
pointer value and assings new_pointer;
*/
template <class T>
void Auto_ptr<T>::reset(T* v) {
delete value;
value = v;
}
#endif
main.cpp:
#include <iostream>
#include "smart_ptr.h"
#include "assert.h"
//=====================================================================
void test1 () {
std::cout <<"\nTest constructor and get() member.\n";
Auto_ptr<int> p(new int);
*p.get() = 5;
std::cout <<"p points to: "<< *p << "\n";
//assert(*p, 5);
std::cout <<"TEST 1 DONE\n";
}
void test2 () {
std::cout <<"\nTest reset() and release() members.\n";
Auto_ptr<int> p(new int);
*p.get() = 5;
std::cout <<"p points to: "<< *p << "\n";
p.reset(new int(10));
std::cout <<"reset() p points to: "<< *p << "\n";
//assert(*p, 10);
int *temp = p.release();
std::cout <<"caller of release(), temp points to: "<< *temp << "\n";
//assert(*temp, 10);
// nullptr dereferece error
// std::cout <<"p after being release()d points to: "<< *p << "\n";
std::cout <<"TEST 2 DONE\n";
}
void test3 () {
std::cout <<"\nTest copy constructor and copy assignment.\n";
Auto_ptr<int> p1(new int(10));
Auto_ptr<int> p2(p1);
std::cout <<"copy constructed p2 points to: "<< *p2 << "\n";
//assert(*p2, 10);
Auto_ptr<int> p3(new int(20));
p1 = p3;
std::cout <<"copy assigned p1 points to: "<< *p1 << "\n";
//assert(*p1, 20);
std::cout <<"TEST 3 DONE\n";
}
//=====================================================================
int main () {
test1 ();
test2 ();
test3 ();
getchar();
}
The interesting note is that in the Live example the error in not reproducible.
What could be the cause of this message ?
This is generally the result of a "double delete" - in this case I suspect it is your copy assignment.
You assign value = p.value; and both copies hold the same value and both attempt to delete it.
You essentially need to move the pointer from one object to the other, as is the case with the copy constructor. You will also need to remove the const as well.
When I override copy constructor why it segfaults in first delete itself.
output:
$./a.out
inside ctor
inside copy-ctor
Say i am in someFunc
inside dtor
*** glibc detected *** ./a.out: free(): invalid pointer: 0xb75f3000 ***
if I do not override copy-ctor then I could see that s1.PrintVal() is getting called and then there is seg fault in *ptr that is expected.
Why there is two different behavior with and without default and overridden copy-ctor?
#include<iostream>
using namespace std;
class Sample
{
public:
int *ptr;
Sample(int i)
{
cout << "inside ctor" << endl;
ptr = new int(i);
}
Sample(const Sample &rhs)
{
cout << "inside copy-ctor" << endl;
}
~Sample()
{
cout << "inside dtor" << endl;
delete ptr;
}
void PrintVal()
{
cout <<" inside PrintVal()."<<endl;
cout << "The value is " << *ptr<<endl;
}
};
void SomeFunc(Sample x)
{
cout << "Say i am in someFunc " << endl;
}
int main()
{
Sample s1= 10;
SomeFunc(s1);
s1.PrintVal();
return 0;
}
In your copy-ctor, you don't actually copy ptr, meaning its value will be unspecified, and you'll be deleting an unspecified pointer (instead of double-deleting a normal pointer as you do with the defauly copy-ctor).
The default copy ctor copies every member by value. This will create an alias to the pointer so each class when its dtor is called will delete the pointer and cause a fault.
In almost any class where you have a pointer that is being allocate you will need to write a custom copy constructor to allocate the pointer and then copy the value.
class Sample
{
public:
int *ptr;
Sample(int i)
{
cout << "inside ctor" << endl;
ptr = new int(i);
}
Sample(const Sample &rhs)
{
ptr = new int(*rhs.ptr);
}
Sample & operator=(const Sample& other)
{
// You should also override copy assignment if you overide copy
// you don't need to allocate in this case just copy the value
*ptr = *other.ptr;
}
~Sample()
{
cout << "inside dtor" << endl;
delete ptr;
}
void PrintVal()
{
cout <<" inside PrintVal()."<<endl;
cout << "The value is " << *ptr<<endl;
}
};
You should look up the rule of three and if your in c++ 11 the rule of five