I have to implement a simple "unique_ptr" class supporting only a constructor, destructor, –>, *, and release(). And I did below.
However, it feels weird to write "up.operator->()" to get the pointer p. I would be more logical to write "up->p". But how do I do that? Thanks!
#include <iostream>
#include <stdexcept>
template <class T>
class unique_ptr
{
T *p;
public:
unique_ptr(T *ptr)
: p{ptr}
{
}
~unique_ptr() { delete p; }
T *operator->() const { return p; } // returns a pointer
T operator*() const { return *p; }
T *release()
{
T *ptr = p;
p = nullptr;
return ptr;
}
};
template <class T>
void print(const unique_ptr<T> &up, const std::string &s)
{
std::cout << s << " up.operator->(): " << up.operator->() << '\n';
std::cout << s << " up.operator*(): " << up.operator*() << '\n';
}
int main()
try
{
int *ptr = new int(10);
unique_ptr<int> up(ptr);
print(up, "up: ");
}
catch (std::exception &e)
{
std::cerr << "exception: " << e.what() << '\n';
return 1;
}
catch (...)
{
std::cerr << "exception\n";
return 2;
}
However, it feels weird to write "up.operator->()" to get the pointer p.
It feels weird because the member access operator is not generally used to get a pointer to the object (although you can do it using the operator->() syntax, as you demonstrated). Member access operator is used to access members of the object. In your example, you have a unique pointer of int. int doesn't have a member, so it doesn't make sense to use the member access operator.
Here is an example of how to use it:
struct S {
int member;
};
unique_ptr<S> up(new S{10});
int value_of_member = up->member;
would be more logical to write "up->p"
That wouldn't be logical unless p is a member of the pointed object.
How to create an operator-> for a class unique_ptr
Like you did in the example. As far as I can tell, there was no problem with how you create the operator, but rather how to use it.
P.S. Your unique pointer is copyable, movable and assignable, but those operations are horribly broken leading to undefined behaviour. See rule of 5.
As others have noted in comments this implementation of a single ownership smart pointer is incomplete and the operator*() is incorrect in that it doesn't return a reference and thus does not facilitate making assignments through the pointer.
However to answer the question,
it feels weird to write "up.operator->()" to get the pointer p. I
would be more logical to write "up->p". But how do I do that?
Well you wouldnt want to do that as p is part of the private implementation of your smart pointer class. It is weird to write up.operator->() because that is not how the -> is typically used. It is typically used as shorthand to access the members of a struct or class that is slightly less verbose than the * operator in combination with member access via .. To use your pointer then in a less weird way you need the template parameter to be instantiated with some type that has fields, e.g.
struct foo {
int bar;
};
void print(const unique_ptr<foo>& up, const std::string& s)
{
std::cout << s << " up.operator->(): " << up->bar << '\n';
std::cout << s << " up.operator*(): " << (*up).bar << '\n';
}
int main()
{
unique_ptr<foo> up(new foo{ 42 });
print(up, "up: ");
}
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;
}
This question already has an answer here:
Placement new and assignment of class with const member
(1 answer)
Closed 4 years ago.
The 2 print statements print different numbers. As far as I can see I'm not doing any dodgy const_cast here so I'm not sure what UB I could have possibly committed.
Is this code well-formed?
Can the compiler rely on the fact that A::num is const so it's allowed to print the same number ?
Code:
struct A
{
const int num = 100;
A() {}
A(int in) : num{in} {}
void call()
{
new (this) A{69};
}
};
int main()
{
A a;
std::cout << a.num << '\n';
a.call();
std::cout << a.num << '\n';
}
No, your code has UB. Remove the const on num and you don't get any UB anymore.
The problem is that the standard provides a guarantee that a const object doesn't change. But if you reuse the same storage, then you can "modify" the const object in a way.
[basic.life]p8 explicitly prohibits this by saying that the old name of the object only refers to the new object under certain conditions. One of them is that your class doesn't have any const members. So by extension, your second a.num is UB, as the a refers to the old destructed object.
However, there are two ways to avoid this UB. First, you can store the pointer to the new object:
struct A *new_ptr;
struct A {
// [...]
void call() {
new_ptr = new (this) A{69};
}
};
int main()
{
A a;
std::cout << a.num << '\n';
a.call();
std::cout << new_ptr->num << '\n'; // ok
}
Or use std::launder:
std::cout << std::launder(&a)->num << '\n'; // second access
Consider we create the array using this way:
T* arr = new T[num];
And now because of some reasons we understood that we need simply delete that array but without calling any T destructors.
We all know that if we write next:
delete arr;
the T destructor will be called.
If we write this:
delete[] arr;
the num destructors would be called.
Having played with pointers, you realize that new inserts before the result pointer the unsigned long long value that represents the number of allocated T instances. So we try to outwit the C++ trying to change that value to number of bytes that arr occupies and delete it as (char*) in hope that in this case the delete would not call the destructors for T instances and simply free occupied memory. So you write something like this:
typedef unsigned long long;
unsll & num = *(unsll)((char*)arr-sizeof(unsll));
num = num*sizeof(T);
delete ((char*)arr);
But that doesn't work and C++ creates the trigger breakpoint(run time error) when trying to delete this. So that doesn't work. And a lot of other playing with pointers doesn't work as at least some error(compile- or run-time) occurs. So the question is:
Is that possible to delete an array of classes in C++ without calling their destructors?
Perhaps you want ::operator delete[](arr).
(See http://en.cppreference.com/w/cpp/memory/new/operator_delete)
But this still has undefined behaviour, and is a terrible idea.
One simple way to deallocate without calling destructors is to separate allocation and initialization. When you take proper care of alignment you can use placement new (or the functionality of a standard allocator object) to create the object instances inside the allocated block. Then at the end you can just deallocate the block, using the appropriate deallocation function.
I can't think of any situation where this would be a smart thing to do: it smells strongly of premature optimization and X/Y-problem (dealing with problem X by imagining impractical Y as a solution, then asking only about Y).
A new-expression is designed to couple allocation with initialization, so that they're executed as an all-or-nothing operation. This coupling, and ditto coupling for cleanup and deallocation, is key to correctness, and it also simplifies things a lot (i.e., inside there's complexity that one doesn't have to deal with). Uncoupling needs to have a very good reason. Avoiding destructor calls, for e.g. purposes of optimization, is not a good reason.
I'm only going to address your specific question of
Is that possible to delete an array of classes in C++ without calling their destructors?
The short answer is yes.
The long answer is yes, but there's caveats and considering specifically what a destructor is for (i.e. resource clean up), it's generally a bad idea to avoid calling a class destructor.
Before I continue the answer, it should be noted that this is specifically to answer your question and if you're using C++ (vs. straight C), using this code will work (since it's compliant), but if you're needing to produce code in this way, you might need to rethink some of your design since code like this can lead to bugs/errors and general undefined behavior if not used properly.
TL;DR if you need to avoid destructors, you need to rethink your design (i.e. use copy/move semantics or an STL container instead).
You can use malloc and free to avoid constructor and destructor calls, example code:
#include <iostream>
#include <cstdio>
class MyClass {
public:
MyClass() : m_val(0)
{
this->init(42);
std::cout << "ctor" << std::endl;
}
~MyClass()
{
std::cout << "dtor" << std::endl;
}
friend std::ostream& operator<<(std::ostream& stream, const MyClass& val)
{
stream << val.m_val;
return stream;
}
void init(int val)
{
/* just showing that the this pointer is valid and can
reference private members regardless of new or malloc */
this->_init(val);
}
private:
int m_val;
void _init(int val)
{
this->m_val = val;
}
};
template < typename Iterator >
void print(Iterator begin, Iterator end)
{
while (begin != end) {
std::cout << *begin << std::endl;
++begin;
}
}
void set(MyClass* arr, std::size_t count)
{
for (; count > 0; --count) {
arr[count-1].init(count);
}
}
int main(int argc, char* argv[])
{
std::cout << "Calling new[10], 10 ctors called" << std::endl;
MyClass* arr = new MyClass[10]; // 10 ctors called;
std::cout << "0: " << *arr << std::endl;
set(arr, 10);
print(arr, arr+10);
std::cout << "0: " << *arr << std::endl;
std::cout << "Calling delete[], 10 dtors called" << std::endl;
delete[] arr; // 10 dtors called;
std::cout << "Calling malloc(sizeof*10), 0 ctors called" << std::endl;
arr = static_cast<MyClass*>(std::malloc(sizeof(MyClass)*10)); // no ctors
std::cout << "0: " << *arr << std::endl;
set(arr, 10);
print(arr, arr+10);
std::cout << "0: " << *arr << std::endl;
std::cout << "Calling free(), 0 dtors called" << std::endl;
free(arr); // no dtors
return 0;
}
It should be noted that mixing new with free and/or malloc with delete results in undefined behavoir, so calling MyClass* arr = new MyClass[10]; and then call free(arr); might not work as "expected" (hence the UB).
Another issue that will arise from not calling a constructor/destructor in C++ is with inheritance. The above code will work with malloc and free for basic classes, but if you start to throw in more complex types, or inherit from other classes, the constructors/destructors of the inherited classes will not get called and things get ugly real quick, example:
#include <iostream>
#include <cstdio>
class Base {
public:
Base() : m_val(42)
{
std::cout << "Base()" << std::endl;
}
virtual ~Base()
{
std::cout << "~Base" << std::endl;
}
friend std::ostream& operator<<(std::ostream& stream, const Base& val)
{
stream << val.m_val;
return stream;
}
protected:
Base(int val) : m_val(val)
{
std::cout << "Base(" << val << ")" << std::endl;
}
void _init(int val)
{
this->m_val = val;
}
int m_val;
};
class Child : public virtual Base {
public:
Child() : Base(42)
{
std::cout << "Child()" << std::endl;
}
~Child()
{
std::cout << "~Child" << std::endl;
}
void init(int val)
{
this->_init(val);
}
};
template < typename Iterator >
void print(Iterator begin, Iterator end)
{
while (begin != end) {
std::cout << *begin << std::endl;
++begin;
}
}
void set(Child* arr, std::size_t count)
{
for (; count > 0; --count) {
arr[count-1].init(count);
}
}
int main(int argc, char* argv[])
{
std::cout << "Calling new[10], 20 ctors called" << std::endl;
Child* arr = new Child[10]; // 20 ctors called;
// will print the first element because of Base::operator<<
std::cout << "0: " << *arr << std::endl;
set(arr, 10);
print(arr, arr+10);
std::cout << "0: " << *arr << std::endl;
std::cout << "Calling delete[], 20 dtors called" << std::endl;
delete[] arr; // 20 dtors called;
std::cout << "Calling malloc(sizeof*10), 0 ctors called" << std::endl;
arr = static_cast<Child*>(std::malloc(sizeof(Child)*10)); // no ctors
std::cout << "The next line will seg-fault" << std::endl;
// Segfault because the base pointers were never initialized
std::cout << "0: " << *arr << std::endl; // segfault
set(arr, 10);
print(arr, arr+10);
std::cout << "0: " << *arr << std::endl;
std::cout << "Calling free(), 0 dtors called" << std::endl;
free(arr); // no dtors
return 0;
}
The above code is compliant and compiles without error on g++ and Visual Studio, but due to the inheritance, both crash when I try to print the first element after a malloc (because the base class was never initialized).
So you can indeed create and delete an array of objects without calling their constructors and destructors, but doing so results in a slew of extra scenarios you need to be aware of and account for to avoid undefined behavior or crashes, and if this is the case for your code, such that you need to ensure the destructors are not called, you might want to reconsider your overall design (possibly even use an STL container or smart pointer types).
Hope that can help.
std::vector has the member function at() as a safe alternative to operator[], so that bound checking is applied and no dangling references are created:
void foo(std::vector<int> const&x)
{
const auto&a=x[0]; // What if x.empty()? Undefined behavior!
const auto&a=x.at(0); // Throws exception if x.empty().
}
However, std::unique_ptr lacks the corresponding functionality:
void foo(std::unique_ptr<int> const&x)
{
const auto&a=*x; // What if bool(x)==false? Undefined behavior!
}
It would be great, if std::unique_ptr had such a safe alternative, say member ref() (and cref()) which never returns a dangling reference, but rather throws an exception. Possible implementation:
template<typename T>
typename add_lvalue_reference<T>::type
unique_ptr<T>::ref() const noexcept(false)
{
if(bool(*this)==false)
throw run_time_error("trying to de-refrence null unique_ptr");
return this->operator*();
}
Is there any good reason why the standard doesn't provide this sort of thing?
unique_ptr was specifically designed as a lightweight pointer class with null-state detection (e.g. stated in optional in A proposal to add a utility class to represent optional objects (Revision 3))
That said, the capability you're asking is already in-place since operator* documentation states:
// may throw, e.g. if pointer defines a throwing operator*
typename std::add_lvalue_reference<T>::type operator*() const;
The pointer type is defined as
std::remove_reference<Deleter>::type::pointer if that type exists, otherwise T*
Therefore through your custom deleter you're able to perform any on-the-fly operation including null pointer checking and exception throwing
#include <iostream>
#include <memory>
struct Foo { // object to manage
Foo() { std::cout << "Foo ctor\n"; }
Foo(const Foo&) { std::cout << "Foo copy ctor\n"; }
Foo(Foo&&) { std::cout << "Foo move ctor\n"; }
~Foo() { std::cout << "~Foo dtor\n"; }
};
struct Exception {};
struct InternalPtr {
Foo *ptr = nullptr;
InternalPtr(Foo *p) : ptr(p) {}
InternalPtr() = default;
Foo& operator*() const {
std::cout << "Checking for a null pointer.." << std::endl;
if(ptr == nullptr)
throw Exception();
return *ptr;
}
bool operator != (Foo *p) {
if(p != ptr)
return false;
else
return true;
}
void cleanup() {
if(ptr != nullptr)
delete ptr;
}
};
struct D { // deleter
using pointer = InternalPtr;
D() {};
D(const D&) { std::cout << "D copy ctor\n"; }
D(D&) { std::cout << "D non-const copy ctor\n";}
D(D&&) { std::cout << "D move ctor \n"; }
void operator()(InternalPtr& p) const {
std::cout << "D is deleting a Foo\n";
p.cleanup();
};
};
int main()
{
std::unique_ptr<Foo, D> up(nullptr, D()); // deleter is moved
try {
auto& e = *up;
} catch(Exception&) {
std::cout << "null pointer exception detected" << std::endl;
}
}
Live Example
For completeness' sake I'll post two additional alternatives/workarounds:
Pointer checking for a unique_ptr via operator bool
#include <iostream>
#include <memory>
int main()
{
std::unique_ptr<int> ptr(new int(42));
if (ptr) std::cout << "before reset, ptr is: " << *ptr << '\n';
ptr.reset();
if (ptr) std::cout << "after reset, ptr is: " << *ptr << '\n';
}
(This would probably be the clanest way to deal with the issue)
An alternative solution, although messier, is to use a wrapper type which takes care of the exception handling
I suspect the real answer is simple, and the same one for lots of "Why isn't C++ like this?" questions:
No-one proposed it.
std::vector and std::unique_ptr are not designed by the same people, at the same time, and are not used in the same way, so don't necessarily follow the same design principles.
I can't say, why the committee decided not to add a safe dereferenciation method - the answer is probably "because it wasn't proposed" or "because a raw pointer hasn't one either". But it is trivial to write a free function template on your own that takes any pointer as an argument, compares it against nullptr and then either throws an excepion or returns a reference to the pointed to object.
If you don't delete it via a pointer to base class, it should be even possible to derive publicly from a unique_ptr and just add such a member function.
Keep in mind however that using such a checked method everywhere might incur a significant performance hit (same as at). Usualy you want to validate your parameters at most once, for which a single if statement at the beginning is much better suited.
There is also the school that says you should not throw exceptions in response to programming errors. Maybe the peopke in charge of designing unique_ptr belonged to this school, while the people designing vector(which is much much older) didn't.
One of the main goals of a smart pointer API design is to be a drop-in replacement with added value, no gotchas or side effects, and close to zero overhead. if (ptr) ptr->... is how safe access to bare pointer is usually done, the same syntax works nicely with smart pointers thus requiring no code change when one is replaced with the other.
An additional check for validity (say, to throw an exception) put inside a pointer would interfere with branch predictor and thus may have a knock-on effect on the performance, which may not be considered a zero cost drop-in replacement anymore.
You do have
operator bool()
Example from:
cplusplusreference
// example of unique_ptr::operator bool
#include <iostream>
#include <memory>
int main () {
std::unique_ptr<int> foo;
std::unique_ptr<int> bar (new int(12));
if (foo) std::cout << "foo points to " << *foo << '\n';
else std::cout << "foo is empty\n";
if (bar) std::cout << "bar points to " << *bar << '\n';
else std::cout << "bar is empty\n";
return 0;
}
unique_ptr is a simple wrapper to a raw pointer, no need to throw an exception when you can just check a boolean condition easily.
Edit:
Apparently operator* can throw.
Exceptions
1) may throw, e.g. if pointer defines a throwing operator*
Maybe someone could shed some lights on hot to define a throwing operator*
Following from the suggestion of MikeMB, here is a possible implementation of a free function for dereferencing pointers and unique_ptrs alike.
template<typename T>
inline T& dereference(T* ptr) noexcept(false)
{
if(!ptr) throw std::runtime_error("attempt to dereference a nullptr");
return *ptr;
}
template<typename T>
inline T& dereference(std::unique_ptr<T> const& ptr) noexcept(false)
{
if(!ptr) throw std::runtime_error("attempt to dereference an empty unique_ptr)");
return *ptr;
}
This question already has answers here:
Why is value taking setter member functions not recommended in Herb Sutter's CppCon 2014 talk (Back to Basics: Modern C++ Style)?
(4 answers)
Closed 7 years ago.
Assume I have the following class, which has a method set_value. Which implementation is better?
class S {
public:
// a set_value method
private:
Some_type value;
};
Pass by value, then move
void S::set_value(Some_type value)
{
this->value = std::move(value);
}
Define two overloaded methods
void S::set_value(const Some_type& value)
{
this->value = value;
}
void S::set_value(Some_type&& value)
{
this->value = std::move(value);
}
The first approach requires definition of one method only while the second requires two.
However, the first approach seems to be less efficient:
Copy/Move constructor for the parameter depending on the argument passed
Move assignment
Destructor for the parameter
While for the second approach, only one assignment operation is performed.
Copy/Move assignment depending on which overloaded method is called
So, which implementation is better? Or does it matter at all?
And one more question: Is the following code equivalent to the two overloaded methods in the second approach?
template <class T>
void S::set_value(T&& value)
{
this->value = std::forward<T>(value);
}
The compiler is free to elide (optimise away) the copy even if there would be side effects in doing so. As a result, passing by value and moving the result actually gives you all of the performance benefits of the two-method solution while giving you only one code path to maintain. You should absolutely prefer to pass by value.
here's an example to prove it:
#include <iostream>
struct XYZ {
XYZ() { std::cout << "constructed" << std::endl; }
XYZ(const XYZ&) {
std::cout << "copy constructed" << std::endl;
}
XYZ(XYZ&&) noexcept {
try {
std::cout << "move constructed" << std::endl;
}
catch(...) {
}
}
XYZ& operator=(const XYZ&) {
std::cout << "assigned" << std::endl;
return *this;
}
XYZ& operator=(XYZ&&) {
std::cout << "move-assigned" << std::endl;
return *this;
}
};
struct holder {
holder(XYZ xyz) : _xyz(std::move(xyz)) {}
void set_value(XYZ xyz) { _xyz = std::move(xyz); }
void set_value_by_const_ref(const XYZ& xyz) { _xyz = xyz; }
XYZ _xyz;
};
using namespace std;
auto main() -> int
{
cout << "** create named source for later use **" << endl;
XYZ xyz2{};
cout << "\n**initial construction**" << std::endl;
holder h { XYZ() };
cout << "\n**set_value()**" << endl;
h.set_value(XYZ());
cout << "\n**set_value_by_const_ref() with nameless temporary**" << endl;
h.set_value_by_const_ref(XYZ());
cout << "\n**set_value() with named source**" << endl;
h.set_value(xyz2);
cout << "\n**set_value_by_const_ref() with named source**" << endl;
h.set_value_by_const_ref(xyz2);
return 0;
}
expected output:
** create named source for later use **
constructed
**initial construction**
constructed
move constructed
**set_value()**
constructed
move-assigned
**set_value_by_const_ref() with nameless temporary**
constructed
assigned
**set_value() with named source**
copy constructed
move-assigned
**set_value_by_const_ref() with named source**
assigned
note the absence of any redundant copies in the copy/move versions but the redundant copy-assignment when calling set_value_by_const_ref() with nameless temporary. I note the apparent efficiency gain of the final case. I would argue that (a) it's a corner case in reality and (b) the optimiser can take care of it.
my command line:
c++ -o move -std=c++1y -stdlib=libc++ -O3 move.cpp