EDIT: I've found out that my question contains a paradox. I used extended initializer list in my code, which was introduced in C++11, but I wanted to use only C++98 tools. Sorry, I noticed my compiler's warning message too late. Of course, move-semantics would have solved my problem in C++11. My question doesn't matter anymore.
I decided to create an own owner_ptr
class. The concept is that an owner_ptr
object has ownership over a dynamically allocated object (or objects). More than 1 owner_ptr
mustn't own the same object. Here is my implementation:
#include <cstddef>
template <typename T>
class owner_ptr
{
T* ptr;
bool array;
public:
owner_ptr() : ptr(NULL) {} /* LINE 10 */
owner_ptr(T* ptr, bool isArray = false) : ptr(ptr), array(isArray) {} /* LINE 11 */
owner_ptr(owner_ptr<T>& orig) : ptr(orig.ptr), array(orig.array) /* LINE 12 */
{
orig.ptr = NULL;
}
~owner_ptr()
{
if (ptr != NULL)
{
if (!array)
{
delete ptr;
}
else
{
delete[] ptr;
}
}
}
owner_ptr& operator=(owner_ptr<T>& rvalue)
{
if (this != &rvalue)
{
this->~owner_ptr();
ptr = rvalue.ptr;
array = rvalue.array;
rvalue.ptr = NULL;
}
return *this;
}
void reset()
{
this->~owner_ptr();
ptr = NULL;
}
void addPtr(T* newPtr, bool isArray = false)
{
this->~owner_ptr();
ptr = newPtr;
array = isArray;
}
T& operator*() { return *ptr; }
const T& operator*() const { return *ptr; }
T* get() { return ptr; }
const T* get() const { return ptr; }
T* operator->() { return ptr; }
const T* operator->() const { return ptr; }
T& operator[](int i) { return ptr[i]; }
const T& operator[](int i) const { return ptr[i]; }
};
I specified that it's the user's responsibility to create legal owner_ptr
objects like:
owner_ptr<int> op1(new int);
owner_ptr<int> op2(new int[3], true);
owner_ptr<int> op3(op1);
owner_ptr<int> op4;
op4 = op3;
It works well with one-dimensional arrays. However, when I try to allocate a two-dimensional array, this code doesn't compile:
int main()
{
owner_ptr< owner_ptr<int> > test(new owner_ptr<int>[2]{ owner_ptr<int>(new int[5], true), owner_ptr<int>(new int[8], true) }, true); /* LINE 72 */
return 0;
}
I got the following messages:
\main.cpp|72|error: no matching function for call to 'owner_ptr<int>::owner_ptr(owner_ptr<int>)'|
\main.cpp|72|note: candidates are:|
\main.cpp|12|note: owner_ptr<T>::owner_ptr(owner_ptr<T>&) [with T = int]|
\main.cpp|12|note: no known conversion for argument 1 from 'owner_ptr<int>' to 'owner_ptr<int>&'|
\main.cpp|11|note: owner_ptr<T>::owner_ptr(T*, bool) [with T = int]|
\main.cpp|11|note: no known conversion for argument 1 from 'owner_ptr<int>' to 'int*'|
\main.cpp|10|note: owner_ptr<T>::owner_ptr() [with T = int]|
\main.cpp|10|note: candidate expects 0 arguments, 1 provided|
\main.cpp|72|error: no matching function for call to 'owner_ptr<int>::owner_ptr(owner_ptr<int>)'|
\main.cpp|72|note: candidates are:|
\main.cpp|12|note: owner_ptr<T>::owner_ptr(owner_ptr<T>&) [with T = int]|
\main.cpp|12|note: no known conversion for argument 1 from 'owner_ptr<int>' to 'owner_ptr<int>&'|
\main.cpp|11|note: owner_ptr<T>::owner_ptr(T*, bool) [with T = int]|
\main.cpp|11|note: no known conversion for argument 1 from 'owner_ptr<int>' to 'int*'|
\main.cpp|10|note: owner_ptr<T>::owner_ptr() [with T = int]|
\main.cpp|10|note: candidate expects 0 arguments, 1 provided|
This is so weird. I have the following questions:
- Why is the compiler looking for a
owner_ptr<int>::owner_ptr(owner_ptr<int>)
function? Such a copy-constructor would make no sense. - Why isn't it possible to convert from
'owner_ptr<int>'
to'owner_ptr<int>&'
? - How can I fix it? Is it possible to allocate a multi-dimensional (using the
owner_ptr
template) with only one command?
I know that this works:
owner_ptr< owner_ptr<int> > test(new owner_ptr<int>[2], true);
test[0].addPtr(new int[5], true);
test[1].addPtr(new int[8], true);
However, I'm curious, is it possible to do it with one command.
NOTE: I'm doing this for learning purposes. This is not a production code. So please, don't recommend me to use the C++11 smart pointers.