I'm trying to overload the new operator in order to allocate my own memory, but I still need to construct the object.
That's why I decided to pass the parameters through a variadic template in order to feed the object's constructor properly.
The constructor is called twice in this example, I can't explain why.
It seems that the overloaded new calls automatically the constructor.
#include <stdlib.h>
#include <iostream>
#include <new>
class A
{
public:
template<typename... Args>
void *operator new(size_t sz, Args ...parameters)
{
void *mem = ::operator new(sizeof(A));
A *var = ::new (mem) A(parameters...);
return var;
}
A() : num(0) { std::cout << "Default" << std::endl; }
A(int nb) : num(nb) { std::cout << "Integer = " << num << std::endl; }
const int num;
};
int main()
{
A *obj = new A(3);
std::cout << "Obj result = " << obj->num << std::endl;
}
Fixed, there is not reason to try to call the constructor within the overload, the object will be constructed at returned void*'s pointed allocated memory.
I'm trying to overload the new operator in order to allocate my own memory, but I still need to construct the object.
No you don't. operator new by definition initializes the object. See [expr.new]/15:
A new-expression that creates an object of type T initializes
that object as follows:
— If the new-initializer is omitted, the object is
default-initialized (8.5); if no initialization is performed, the
object has indeterminate value.
— Otherwise, the new-initializer is interpreted according to the
initialization rules of 8.5 for direct-initialization.
At a minimum, your overload can look like this:
void *operator new(size_t sz)
{
return ::operator new(sizeof(A));
}
The static keyword is optional.
Related
Currently, I'm storing a collection of std::unique_ptrs to heap allocated objects of a polymorphic type:
struct Foo {
virtual ~Foo() = default;
};
Collection<std::unique_ptr<Foo>> foos;
The basic interface I need is putting / taking owners of Foo to / from foos. The objects stored in foos are never supposed to be nullptr so I'd like to replace runtime assert(owner_taken) with compile-time checks. Moreover, I would like to be capable of using non-null owners in the context where a nullable one may be expected.
Probably, I need to store something like unique_ref but how would I extract one from foos? I don't want a copy, I want the stored object itself, so owner->clone() isn't a solution. Neither I can std::move(owner) because the state of a "unique reference" would be invalid afterwards.
Is there a clean design decision?
Is there a never-null unique owner of heap allocated objects?
There is no such type in the standard library.
It is possible to implement such type. Simply define a type with unique_ptr member and mark the default constructor deleted. You can mark constructor from std::nullptr_t deleted also so that construction from nullptr will be prevented at compile time.
Whether you construct from an external pointer, or allocate in the constructor, there is no alternative for checking for null at runtime.
Reading your question, I interpret the following requirements:
You don't want to copy or move the object itself (Foo)
You don't want a wrapper which has some sort of empty state which excludes move semantics
The object itself (Foo) should be stored on the heap such that its lifetime is independent of the control flow
The object itself (Foo) should be deleted once it is not used any more
As construction / destruction, copy and move are the only ways to get objects into / out of a container, the only thing left is a wrapper object which is copied when moved into / out of the container.
You can create such an object yourself as follows:
// LICENSE: MIT
#include <memory>
#include <utility>
template<typename T>
class shared_ref {
public:
template<typename ...Args>
shared_ref(Args&&... args)
: data{new T(std::forward<Args>(args)...)}
{}
shared_ref(shared_ref&&) = delete;
shared_ref& operator=(shared_ref&&) = delete;
T& get() noexcept {
return *data;
}
const T& get() const noexcept {
return *data;
}
operator T&() noexcept {
return get();
}
operator const T&() const noexcept {
return get();
}
void swap(shared_ref& other) noexcept {
return data.swap(other);
}
private:
std::shared_ptr<T> data;
};
template<class T>
void swap(shared_ref<T>& lhs, shared_ref<T>& rhs) noexcept {
return lhs.swap(rhs);
}
I leave it as an exercise to the reader to add support for Allocator, Deleter, operator[], implicit conversion contructor to base classes.
This can then be used as follows:
#include <iostream>
int main() {
shared_ref<int> r; // default initialized
std::cout << "r=" << r << std::endl;
r = 5; // type conversion operator to reference
std::cout << "r=" << r << std::endl;
shared_ref<int> s{7}; // initialized with forwarded arguments
std::cout << "s=" << s << std::endl;
std::swap(r, s);
std::cout << "r=" << r << ", " << "s=" << s << std::endl;
s = r; // copy assignment operator
std::cout << "s=" << s << std::endl;
const shared_ref<int> t{s}; // copy constructor
std::cout << "t=" << t << std::endl;
//t = 8; // const ref from a const object is immutable
return 0;
}
How can you initialize a container to a class with no default? How can you create the array of pointers required without using new or a method which calls the default constructor of a class?
#include <string>
#include <iostream>
#include <vector>
#include "MyVector.h"
class NoDefault {
public:
//NoDefault():value(0){};
NoDefault(const int& value) : value(value) {}
int value;
};
std::ostream& operator<<(std::ostream& out, const NoDefault& noDefault) {
out << noDefault.value;
return out;
}
int main() {
MyVector<int> intVec(10, 99);
MyVector<std::string> stringVec(5, "hi");
MyVector<NoDefault> noDefaultVec(4, -3);
std::vector<std::vector<std::string>> tempRealVec({{"hi", "bye"}, {"sly",
"guy", "why"}});
MyVector<MyVector<std::string> > tempMyVec(tempRealVec);
MyVector<MyVector<MyVector<std::string> > > vecVecVecStringVec(2, tempMyVec);
std::cout << "intVec = " << intVec << std::endl;
std::cout << "stringVec = " << stringVec << std::endl;
std::cout << "noDefaultVec = " << noDefaultVec << std::endl;
std::cout << "vecVecVecStringVec = " << vecVecVecStringVec << std::endl;
std::cout << "hello" << std::endl;
return 0;
}
This is the constructor
template <typename T>
MyVector<T>::MyVector(const unsigned int& numElements,const T& value):data_(new
T[numElements]),size_(numElements)
{
for(int i = 0; i < size_; i++)
{
if(std::is_same<T,int>::value)
data_[i]=T(value);
else if(std::is_same<T,std::string>::value)
data_[i]=T(value);
else if(std::is_same<T,MyVector>::value)
data_[i]=T(value);
else if(std::is_same<T,NoDefault>::value)
data_[i]=T(value);
}
}
the error thrown because of the use of new in initializer list is no matching function for call to NoDefault::NoDefault(), even if i create that constructor, which would defeat the purpose. It then prints the vector with the default value not the value given as the second argument in the call to MyVector.
You can use placement new. Placement new allows you to construct an object in a specific memory location, so the steps look something like this:
Allocate raw memory (malloc or ::operator new both work)
Construct your object in this raw memory (new (ptr) NoDefault{args})
This is roughly how regular new works (allocates memory via ::operator new, then uses placement new to construct the object). I'm not sure if stdl containers like vector are required to use this method, but I'd be a bit surprised if they didn't.
The big caveat (and it is a big one) is that when using placement new you have to manually invoke the destructor (the only time I'm aware of where you intentionally invoke destructors). After the destructors have been called, you're free to release the allocated memory using the appropriate method (e.g., free or ::operator delete).
More information is available from the C++ FAQ.
Helo, I'm new to C++ programming.
I'm not understanding about these line of code...
SomeClass someClassObject(35);
...
someClassObject = SomeClass(46);
first of all,what does "someClassObject = SomeClass(46)" does? Is it like what pointer of SomeClass E.G.: "someClassObject = new SomeClass(46)" does but on stack?
No pointers are involved here. SomeClass(46) constructs a temporary object, typically on the stack. This is followed by an assignment to the variable someClassObject. The exact semantics of this assignment can be user-defined by overloading the assignment operator.
PS: Note the missing semicolons at the end of your statements.
SomeClass(46) constructs a new instance of SomeClass on the stack, by calling the constructor passing the number 46 to it.
someClassObject = some instance of SomeClass call the operator= on someClassObject.
Unless the constructor is declared explicit it could also have been written as:
someClassObject = 46;
Take a look at this example: http://ideone.com/7kgWob pasted below:
#include <iostream>
using namespace std;
class SomeClass
{
private:
int i = 0;
public:
SomeClass() { cout << "default constructor\n"; };
SomeClass(int val) { i = val; cout << "constructor getting int: " << val << '\n'; };
~SomeClass() { cout << "destrucing object having i: " << i << '\n'; };
SomeClass& operator=(const SomeClass& rhs) {
cout << "operator= getting int: " << rhs.i << '\n';
if (this != &rhs) {
i = rhs.i;
}
return *this;
}
};
int main() {
SomeClass a(10);
SomeClass b = SomeClass(20);
SomeClass c(35);
c = SomeClass(46);
return 0;
}
It will output:
constructor getting int: 10
constructor getting int: 20
constructor getting int: 35
constructor getting int: 46
operator= getting int: 46
destrucing object having i: 46
destrucing object having i: 46
destrucing object having i: 20
destrucing object having i: 10
In essence it creates a temporary instance, and sets the current instance to the same value as the temporary (two objects with the same value exists at this point). It then frees the temporary. Since no new is involved it happens on the stack.
SomeClass* someClassObject = new SomeClass(46); you initialized a pointer of type class SomeClass to a dynamic object through calling the constructor that takes an integer.
the second you called the overloaded assignment operator which calls the constructor that takes an integer creating a temporary object thenn assigns it to someClassObject.
don't forget ; it is not arbitrary.
I wanted to restrict a specific class to be creatable on the stack only (not via allocation). The reason for this is that on the stack, the object which lifetime has begun last, will be the first to be destroyed, and I can create a hierarchy. I did it like this:
#include <cstddef>
#include <iostream>
class Foo {
public:
static Foo createOnStack() {
return {};
}
~Foo () {
std::cout << "Destructed " << --i << std::endl;
}
protected:
static int i;
Foo () {
std::cout << "Created " << i++ << std::endl;
}
Foo (const Foo &) = delete;
};
int Foo::i = 0;
The constructor normally should push the hierarchy stack, and the destructor pops it. I replaced it here for proof of concept. Now, the only way you can use such an object is by storing it in a temporary reference like this:
int main() {
Foo && a = Foo::createOnStack();
const Foo& b = Foo::createOnStack();
return 0;
}
My question now is, how safe is this with the C++ standard? Is there still a way to legally create a Foo on the heap or hand it down from your function into another frame (aka return it from your function) without running into undefined behaviour?
EDIT: link to example https://ideone.com/M0I1NI
Leaving aside the protected backdoor, C++17 copy elision breaks this in two ways:
#include<iostream>
#include<memory>
struct S {
static S make() {return {};}
S(const S&)=delete;
~S() {std::cout << '-' << this << std::endl;}
private:
S() {std::cout << '+' << this << std::endl;}
};
S reorder() {
S &&local=S::make();
return S::make();
}
int main() {
auto p=new S(S::make()),q=new S(S::make()); // #1
delete p; delete q;
reorder(); // #2
}
The use of new is obvious and has been discussed.
C++17 also allows prvalues to propagate through stack frames, which means that a local can get created before a return value and get destroyed while that return value is alive.
Note that the second case already existed (formally in C++14 and informally long before) in the case where local is of type S but the return value is some other (movable) type. You can't assume in general that even automatic object lifetimes nest properly.
I am trying to understand overloading new operator. I wrote the code as below.
#include <iostream>
#include <cstdlib>
#include <new>
using namespace std;
class loc
{
int lo, la;
public:
loc()
{
}
loc(int x, int y)
{
cout << "In constructor\n";
lo = x;
la = y;
}
void show()
{
cout << lo << " ";
cout << la << endl;
}
void *operator new(size_t sz);
void operator delete(void *p);
};
void *loc::operator new(size_t sz)
{
cout << "in Overloaded new\n";
void *p = malloc(sz);
return p;
}
void loc::operator delete(void *p)
{
cout << "in Overloaded delete\n";
free(p);
}
int main()
{
loc *p1 = new loc(10, 20);
p1->show();
delete p1;
return 0;
}
I thought it won't call the constructor because I overloaded the new operator with malloc function call inside overloading function. But the output is as below.
in Overloaded new
In constructor
10 20
in Overloaded delete
That means constructor is getting called. How this is possible? Does this mean will malloc() call constructor?
A new expression results in two separate things happening: allocation of the memory needed by the object begin created, and initialization of the object.
The new operator, on the other hand, just handles the allocation part. When you overload the new operator with respect to a specific class, you are replacing the allocation of memory to the object.
This division of functions makes sense when you realize that not all objects are allocated on the heap. Consider the following case:
int main() {
string someString;
..
}
The local variable is not dynamically allocated; new is not used; however the object still needs to be initialized so the constructor is still called. Note that you did not need to explicitly call the constructor - it is implicit in the language that an appropriate constructor will always be called to initialize an object when it is created.
When you write a 'new expression', the compiler knows to emit instructions to invoke the new operator (to allocate memory as needed) and then to call the constructor (to initialize the object). This happens whether or not you overload the new operator.