Disclaimer: This is rather more out of curiosity than for a lack of other solutions!
Is it possible to implement a function in C++ that:
gets passed a pointer of type T
either returns a reference-like-thing to the object pointed to by T
or, if the pointer is null, returns a reference-like-thing to a default constructed T() that has some sane lifetime?
Our first try was:
template<typename T>
T& DefaultIfNullDangling(T* ptr) {
if (!ptr) {
return T(); // xxx warning C4172: returning address of local variable or temporary
} else {
return *ptr;
}
}
A second attempt was done like this:
template<typename T>
T& DefaultIfNull(T* ptr, T&& callSiteTemp = T()) {
if (!ptr) {
return callSiteTemp;
} else {
return *ptr;
}
}
This gets rid of the warning and somewhat extends the lifetime of the temporary, but it's still rather error prone, I think.
Background:
The whole thing was triggered by an access pattern that looked like this:
if (pThing) {
for (auto& subThing : pThing->subs1) {
// ...
if (subThing.pSubSub) {
for (auto& subSubThing : *(subThing.pSubSub)) {
// ...
}
}
}
}
that could be "simplified" to:
for (auto& subThing : DefaultIfNull(pThing).subs1) {
// ...
for (auto& subSubThing : DefaultIfNull(subThing.pSubSub)) {
// ...
}
}
Yes, but it's going to be ugly:
#include <stdio.h>
#include <variant>
template <class T>
struct Proxy {
private:
std::variant<T*, T> m_data = nullptr;
public:
Proxy(T* p) {
if (p)
m_data = p;
else
m_data = T{};
}
T* operator->() {
struct Visitor {
T* operator()(T* t) { return t; }
T* operator()(T& t) { return &t; }
};
return std::visit(Visitor{}, m_data);
}
};
struct Thing1 {
int pSubSub[3] = {};
auto begin() const { return pSubSub; }
auto end() const { return pSubSub + 3; }
};
struct Thing2 {
Thing1* subs1[3] = {};
auto begin() const { return subs1; }
auto end() const { return subs1 + 3; }
};
template <class T>
auto NullOrDefault(T* p) {
return Proxy<T>(p);
}
int main() {
Thing1 a{1, 2, 3}, b{4, 5, 6};
Thing2 c{&a, nullptr, &b};
auto pThing = &c;
for (auto& subThing : NullOrDefault(pThing)->subs1) {
for (auto& subSubThing : NullOrDefault(subThing)->pSubSub) {
printf("%d, ", subSubThing);
}
putchar('\n');
}
}
There isn't really a good, idiomatic C++ solution that would exactly match what you're asking for.
A language where "EmptyIfNull" would work well, is probably one that has either garbage collection, or reference counted objects. So, we can achieve something similar in C++ by using reference counted pointers:
// never returns null, even if argument was null
std::shared_pr<T>
EmptyIfNull(std::shared_pr<T> ptr) {
return ptr
? ptr
: std::make_shared<T>();
}
Alternatively, you could return a reference to an object with static storage duration. However, I would not return a mutable reference when using such technique, since one caller might modify the object to be non-empty which might be highly confusing to another caller:
const T&
EmptyIfNull(T* ptr) {
static T empty{};
return ptr
? *ptr
: empty;
}
Alternatively, you could still return a mutable reference, but document that not modifying the empty object is a requirement that the caller must obey. That would be brittle, but that's par for the course in C++.
As another alternative, I was writing a suggestion to use a type-erasing wrapper that is either a reference, or an object, but Ayxan Haqverdili has got it covered already. Tons of boilerplate though.
Some alternative designs that adjust the premise a bit more, to be suitable to C++:
Return an object:
T
EmptyIfNull(T* ptr) {
return ptr
? *ptr
: T{};
}
Let the caller provide the default:
T&
ValueOrDefault(T* ptr, T& default_) {
return ptr
? *ptr
: default_;
}
Treat a non-null argument as a pre-condition:
T&
JustIndirectThrough(T* ptr) {
assert(ptr); // note that there may be better alternatives to the standard assert
return *ptr;
}
Treat a null argument as an error case:
T&
JustIndirectThrough(T* ptr) {
if (!ptr) {
// note that there are alternative error handling mechanisms
throw std::invalid_argument(
"I can't deal with this :(");
}
return *ptr;
}
Background:
I don't think the function that you're asking for is very attractive for the background that you give. Currently, you do nothing if the pointer is null, while with this suggestion you would be doing something with an empty object. If you dislike the deeply nested block, you could use this alternative:
if (!pThing)
continue; // or return, depending on context
for (auto& subThing : pThing->subs1) {
if (!subThing.pSubSub)
continue;
for (auto& subSubThing : *subThing.pSubSub) {
// ...
}
}
Or, perhaps you could establish an invariant that you never store null in the range, in which case you never need to check for null.
Sadly, but no. There is really no way to fully achieve what you want. Your options are:
If passed pointer is nullptr, return a reference to static object. This would only be correct if you are returning a const reference, otherwise, you are exposing yourself to a huge can of worms;
Return an std::optional<std::ref> and return unset optional if pointer is nullptr. This doesn't really solve your problem, as you still have to check at the call site if the optional is set, and you might as well check for the pointer to be nullptr instead at the call site. Alternatively, you can use value_or to extract value from optional, which would be akin to next option in a different packaging;
Use your second attempt, but remove default argument. This will mandate call site to provide a default object - this makes code somewhat ugly
If you only want to skip over nullptrs easily, you could just use boost::filter_iterator.
Now, this does not return default value on null pointer occurence, but neither does OP's original code; instead it wraps the container and provides the API to silently skip it in the for loop.
I skipped all the boilerplate code for brevity, hopefully the snippet below illustrates the idea well.
#include <iostream>
#include <memory>
#include <vector>
#include <boost/iterator/filter_iterator.hpp>
struct NonNull
{
bool operator()(const auto& x) const { return x!=nullptr;}
};
class NonNullVectorOfVectorsRef
{
public:
NonNullVectorOfVectorsRef(std::vector<std::unique_ptr<std::vector<int>>>& target)
: mUnderlying(target)
{}
auto end() const
{
return boost::make_filter_iterator<NonNull>(NonNull(), mUnderlying.end(), mUnderlying.end());
}
auto begin() const
{
return boost::make_filter_iterator<NonNull>(NonNull(), mUnderlying.begin(), mUnderlying.end());
}
private:
std::vector<std::unique_ptr<std::vector<int>>>& mUnderlying;
};
int main(int, char*[])
{
auto vouter=std::vector<std::unique_ptr<std::vector<int>>> {};
vouter.push_back(std::make_unique<std::vector<int>>(std::vector<int>{1,2,3,4,5}));
vouter.push_back(nullptr);
vouter.push_back(std::make_unique<std::vector<int>>(std::vector<int>{42}));
auto nn = NonNullVectorOfVectorsRef(vouter);
for (auto&& i:nn) {
for (auto&& j:(*i)) std::cout << j << ' ';
std::cout << '\n';
}
return 0;
}
If you accept std::shared_ptr<T>, you could use them to achieve this in a rather save and portable way:
template<typename T>
std::shared_ptr<T> NullOrDefault(std::shared_ptr<T> value)
{
if(value != nullptr)
{
return value;
}
return std::make_shared<T>();
}
From the comments:
One solution would be to implement a proxy range type containing a
pointer. This type would provide the begin and end members which
either forward the call to the pointed container or provide an empty
range. The usage would be basically identical to using a NullOrEmpty
function, in the context of a range-based for loop. – François
Andrieux yesterday
This is basically similar to what Ayxan provided in another answer, though this one here does work with exactly the client side syntax shown in the OP by providing begin() and end():
template<typename T>
struct CollectionProxy {
T* ref_;
// Note if T is a const-type you need to remove the const for the optional, otherwise it can't be reinitialized:
std::optional<typename std::remove_const<T>::type> defObj;
explicit CollectionProxy(T* ptr)
: ref_(ptr)
{
if (!ref_) {
defObj = T();
ref_ = &defObj.value();
}
}
using beginT = decltype(ref_->begin());
using endT = decltype(ref_->end());
beginT begin() const {
return ref_->begin();
}
endT end() const {
return ref_->end();
}
};
template<typename T>
CollectionProxy<T> DefaultIfNull(T* ptr) {
return CollectionProxy<T>(ptr);
}
void fun(const std::vector<int>* vecPtr) {
for (auto elem : DefaultIfNull(vecPtr)) {
std::cout << elem;
}
}
Notes:
Allowing for T and T const seems a wee bit tricky.
The solution using a variant would generate a smaller proxy object size (I think).
This is certainly gonna be more expensive at runtime than the if+for in the OP, after all you have to at least construct an (empty) temporary
I think providing an empty range could be done cheaper here if all you need is begin() and end(), but if this should generalize to more than just calls to begin() and end(), you would need a real temporary object of T anyways.
Related
I'm trying to create a not-null unique_ptr.
template <typename T>
class unique_ref {
public:
template <class... Types>
unique_ref(Types&&... Args) { mPtr = std::make_unique<T, Types...>(std::forward<Types>(Args)...); }
T* release() && { return mPtr.release(); }
T* release() & = delete;
private:
std::unique_ptr<T> mPtr;
};
My goal is to allow release() only if the unique_ref is a temporary.
The problem is someone could use std::move() to "get around" this:
unique_ref<int> p;
int* p2 = std::move(p).release();
Is there a way to prevent it from being move'd?
There is no way of distinguishing prvalues (temporaries) from xvalues (result of std::move) as far as overload resolution is concerned.
And there is no way of preventing std::move from converting an lvalue to an xvalue.
release is not an operation that can be supported by a non-null-guarantee "unique pointer". And neither is move construction / assignment. As far as I can tell, the only way to make the guarantee is to make the pointer non-movable, and make the copy operation allocate a deep copy.
You're going to have to let the std::move case go. When a user invokes std::move, they are giving a strong signal that they know exactly what they are doing.
You can protect yourself though during debug time.
For example, I would consider starting the class definition a little like this:
#include <memory>
#include <cassert>
template <typename T>
class unique_ref {
public:
// a number of problems here, but that is a discussuion for another day
template <class... Types>
unique_ref(Types&&... Args)
: mPtr(std::make_unique<T>(std::forward<Types>(Args)...))
{ }
// unique_ref is implicitly move-only
// see check below
bool has_value() const {
return bool(mPtr);
}
// here I am implicitly propagating the container's constness to the
// inner reference yielded. You may not want to do that.
// note that all these accessors are marshalled through one static function
// template. This gives me control of behaviour in exactly one place.
// (DRY principles)
auto operator*() -> decltype(auto) {
return *get_ptr(this);
}
auto operator*() const -> decltype(auto) {
return *get_ptr(this);
}
auto operator->() -> decltype(auto) {
return get_ptr(this);
}
auto operator->() const -> decltype(auto) {
return get_ptr(this);
}
private:
using implementation_type = std::unique_ptr<T>;
implementation_type release() { return std::move(mPtr); }
// this function is deducing constness of the container and propagating it
// that may not be what you want.
template<class MaybeConst>
static auto get_ptr(MaybeConst* self) -> decltype(auto)
{
auto ptr = self->mPtr.get();
assert(ptr);
using self_type = std::remove_pointer_t<decltype(self)>;
if constexpr (std::is_const<self_type>())
return static_cast<T const*>(ptr);
else
return ptr;
}
private:
implementation_type mPtr;
};
struct foo
{
};
auto generate()->unique_ref<foo> {
return unique_ref<foo>();
}
void test()
{
auto rfoo1 = generate();
auto rfoo2 = generate();
// auto rfoo3 = rfoo1; not copyable
// we have to assume that a user knows what he's doing here
auto rfoo3 = std::move(rfoo1);
// but we can add a check
assert(!rfoo1.has_value());
auto& a = *rfoo3;
static_assert(!std::is_const<std::remove_reference_t<decltype(a)>>());
const auto rfoo4 = std::move(rfoo3);
auto& b = *rfoo4;
static_assert(std::is_const<std::remove_reference_t<decltype(b)>>());
}
Consider the following example:
class Foo {
public:
std::vector<Item*> items = { nullptr, new Item(), new Item(), nullptr };
// function to return all non-nullptr items as an iterator
};
int main() {
Foo foo;
for (Item* i : foo.functionToReturnIteratorOverAllNullItems)
// do something
}
Is it possible to create a function inside the class to return the items in a std::vector also residing in the class, but skipping nullptr items? Or any other items for that matter. I am thinking some lambda function usage would make this work but I am not sure how.
Note I want it to be efficient without re-creating any other new vector and return that. Should preferably work in C++11.
You could use boost::adaptors::filtered (or ranges::view::filter):
// pipe version
for (Item* i : foo.items | filtered([](Item* i){return i;})) {
// ...
}
// function version
for (Item* i : filter(foo.items, [](Item* i){return i;})) {
// ...
}
This is one of the easier range adaptors to write yourself if you want a challenge. You just need an iterator type that does something slightly more complicated than forward along ++ for operator++().
But it's probably easier to just use an if statement, no?
for (Item* i : foo.items) {
// either positive
if (i) {
// ...
}
// or negative
if (!i) continue;
// ...
}
Here's an alternative approach using higher-order functions and lambdas that abstracts the filtering logic. It does not require any additional dependency.
template <typename TContainer, typename TF>
auto for_nonnull_items(TContainer&& container, TF f)
{
for(auto&& i : container)
{
if(i == nullptr) continue;
f(i);
}
return f;
}
std::vector<int*> example{/*...*/};
for_nonnull_items(example, [](auto ptr)
{
// do something with `ptr`
});
By calling for_nonnull_items(this->items, /*...*/) inside foo you can achieve a nicer interface:
foo.for_nonnull_items([](auto ptr)
{
// do something with `ptr`
});
Deriving from std::iterator makes custom iterators fairly trivial. In this case I have implemented a forward_only iterator. Add more features as you see fit.
#include <iterator>
template<class Iter>
struct non_null_forward_iterator : std::iterator<std::forward_iterator_tag, typename Iter::value_type>
{
using value_type = typename Iter::value_type;
non_null_forward_iterator(Iter i, Iter last) : iter_(i), last_(last)
{
seek();
}
value_type operator*() const {
return *iter_;
}
non_null_forward_iterator& operator++() {
++iter_;
seek();
return *this;
}
void seek()
{
while (iter_ != last_) {
if (*iter_)
break;
++iter_;
}
}
bool operator==(const non_null_forward_iterator& r) const {
return iter_ != r.iter_;
}
bool operator!=(const non_null_forward_iterator& r) const {
return iter_ != r.iter_;
}
Iter iter_;
Iter last_;
};
template<class Container>
auto non_null_range(const Container& cont)
{
using underlying_iter_type = typename Container::const_iterator;
using iter_type = non_null_forward_iterator<underlying_iter_type>;
struct X {
iter_type begin() const { return begin_; }
iter_type end() const { return end_; }
iter_type begin_;
iter_type end_;
};
return X {
iter_type(cont.begin(), cont.end()),
iter_type(cont.end(), cont.end())
};
}
struct Item {};
std::ostream& operator<<(std::ostream& os, const Item& item)
{
return std::cout << "an item";
}
int main()
{
std::vector<Item*> items = { nullptr, new Item(), new Item(), nullptr };
for (auto p : non_null_range(items))
{
std::cout << *p << std::endl;
}
}
expected output:
an item
an item
This answer to another SO question provides a solution that works here. The accepted answer to the question does not.
This implements a generic filter helper in C++14.
for( auto ptr: filter([](auto&& x){return x!=nullptr;})( test ) )
will loop over the elements of test such that x!=nullptr.
Doing this in C++11 mostly consists of filling in the return types. The exception is the final filter function, which returns a lambda, which is impossible in C++11, and the use of auto&& in the lambda above.
Many C++11 compilers support auto parameters to lambdas. Those that do not, you can fold the returned lambda of filter and its argument into the filter function itself, and then write out the tedious return value.
C++2x TS has coroutines which make this trivial. The code will look roughly like:
std::generator<Item*> non_null_items() {
for( Item* i : items )
if ( i ) co_return i;
}
as a method within your class.
This mirrors similar C# and python syntax.
I have the following functions:
private:
static char* new_data(std::size_t size) { return new char[size]; }
template<typename T> static char* new_data(T& value) { return reinterpret_cast<char*>(new (new_data(sizeof(T))) T(value)); }
template<typename T> static char* new_data(T&& value) { return reinterpret_cast<char*>(new (new_data(sizeof(T))) T(value)); }
static void delete_data(char* data) { return delete[] data; }
(Note: T is any type, except it won't overload any form of new or delete)
These functions are only used as part of a RAII-like struct, so there should not been any memory leaks caused by using them.
I am concerned about the safety of this, specifically with regards to alignment (as an array suitably aligned for char might not be properly aligned for T).
My questions is this:
What can I do to make my code perfectly safe? If it already is, why is it?
EDIT:
I am also assuming here that 'T' has a trivial destructor (well all the types I'm currently using do...)
Also with regards to new_data(std::size_t size)` I am only using it when I am going to manual construct the values (because the corresponding 'type' is to be generated at run time, which will not require allignment)
EDIT: Telling me to use smart pointers is not an answer just because using someone else's code could make my code smaller, that does not make it better (primarily due to efficiency and ease of use).
EDIT: I have decided to use the following modified code:
struct Constant
{
template<typename T, typename... Targs> static Constant&& construct(Targs... args...)
{
return Constant(sizeof(T), new(new char[sizeof(T)]) T(args...));
}
template<typename T> static Constant&& construct_default()
{
return Constant(sizeof(T), new(new char[sizeof(T)]) T);
}
template<typename T, typename... Targs> static Constant&& construct_list(Targs... args...)
{
return Constant(sizeof(T), new(new char[sizeof(T)]) T{args...});
}
Constant()
: Constant(0, nullptr, nullptr) { }
explicit Constant(std::size_t size, Syntax::Expression* creator = nullptr)
: Constant(size, new char[size], creator) { allocate(); }
Constant(const Constant& c)
: Constant(c.size_value, c.data_pointer, c.creator) { allocate(); }
Constant(Constant&& c)
: Constant(c.size_value, c.data_pointer, c.creator) { c.data_pointer = nullptr; }
private:
std::size_t size_value = 0;
char* data_pointer = nullptr;
public:
Syntax::Expression* creator = nullptr;
std::size_t size() const { return size_value; }
template<typename T = char*> T data() { return reinterpret_cast<T>(data_pointer); }
template<typename T = const char*> T data() const { return reinterpret_cast<T>(data_pointer); }
template<typename T> Constant&& copy() const
{
return Constant(size_value, new (new char[sizeof(T)]) T(*reinterpret_cast<T*>(data_pointer)), creator);
}
template<typename T> Constant&& copy(Syntax::Expression* e) const
{
return Constant(size_value, new (new char[sizeof(T)]) T(*reinterpret_cast<T*>(data_pointer)), e);
}
Constant&& raw_copy() const
{
return Constant(size_value, std::memcpy(new char[size_value], data_pointer, size_value), creator);
}
Constant&& raw_copy(Syntax::Expression* e) const
{
return Constant(size_value, std::memcpy(new char[size_value], data_pointer, size_value), e);
}
Constant& operator =(const Constant& c)
{
deallocate();
size_value = c.size_value;
data_pointer = c.data_pointer;
creator = c.creator;
allocate();
return *this;
}
Constant& operator =(Constant&& c)
{
deallocate();
size_value = c.size_value;
data_pointer = c.data_pointer;
creator = c.creator;
c.data_pointer = nullptr;
return *this;
}
~Constant() { deallocate(); }
private:
Constant(std::size_t size, void* data, Syntax::Expression* creator = nullptr)
: size_value(size), data_pointer(reinterpret_cast<char*>(data)), creator(creator) { }
static std::map<void*, std::size_t> allocation_table;
void allocate() const
{
if (data_pointer == nullptr)
return;
if (allocation_table.count(data_pointer) == 0)
allocation_table[data_pointer] = 1;
else allocation_table[data_pointer]++;
}
void deallocate() const
{
if (data_pointer == nullptr)
return;
if ((allocation_table[data_pointer] -= 1) == 0)
{
delete[] data_pointer;
allocation_table.erase(data_pointer);
}
}
};
std::map<void*, std::size_t> Constant::allocation_table = {};
Thank you to everyone who helped me. Though my question was never actually fully answered, based on my reading on http://en.cppreference.com/w/cpp/memory/new/operator_new and http://en.cppreference.com/w/cpp/language/new, I am pretty sure my code is safe (though not certain). Also I may have the ... syntax completely wrong, but I should find out when I actually try and compile it (and use it).
You're basically reinventing:
T* t = new T(value);
T* u = new T(std::move(value));
except it's much less functional, because I can't use any other constructor of T besides copy and move. Not even default! (Note also that your second constructor is incorrect - you should forward from value, not copy it, and having a forwarding-reference constructor makes having an lvalue reference constructor redundant. Also you want to create a decay_t<T>, not a T - because T can be a reference type).
And it's much less safe because... well, what do I do with t and u at the end? You would call delete_data(). That frees the memory, but it doesn't destroy the objects. You're missing a destructor call. delete t does both for you.
Basically, this gives you no advantage and a few important disadvantages over just normal raw new and delete. And modern C++ has tools that have advantages over those: smart pointers. When in doubt, use those instead.
It's also worth pointing out, that these two overloads:
static char* new_data(std::size_t size);
template<typename T> static char* new_data(T&& value);
do wildly different things in a way that could be very confusing. new_data(42) allocates 4 bytes and placement-news 42 into there. new_data((size_t)42) allocates 42 bytes. That's just very error prone.
You could allocate std::max_align_t instead of char, in order to have safely-aligned objects.
However, this doesn't address the issue that neither constructors, nor destructors, are going to get invoked here.
RAII is already a solved issue. There is no reason to reinvent this wheel, in some odd manner. Use containers, and/or std::shared_ptr, and your code will be RAII-safe, by default.
I need to find a way to test my exception handling in a function I wrote called hpx::parallel::copy. Other functions in the library such as hpx::parallel::transform are easy to test as a predicate can be passed in which throws an exception, but copy takes no predicate.
I think my best solution would be to use an iterator that throws on dereference somehow, though I'm not quite sure how to go about doing this......any other suggestions to solving this problem are welcome as well. Here is a code example of my problem
//transform.cpp , testing exceptions
bool caught_exception = false;
try {
base_iterator outiter = hpx::parallel::transform(policy,
iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d),
[](std::size_t v) { //easy, predicate can be passed
throw std::runtime_error("test");
return v;
});
HPX_TEST(false);
}
//catching exceptions etc...
//copy.cpp, testing exceptions
bool caught_exception = false;
try {
base_iterator outiter = hpx::parallel::copy(policy,
iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d)); //no predicate... how can I throw?
HPX_TEST(false);
}
//catching exceptions etc..
to be more specific, I want to be able to modify what exactly I want to throw in order to test multiple scenarios, this just means I can't use an implementation that throws out of range or other exceptions I can't control, I need to throw specific exceptions.
An approach different from constructing your own iterators would be to construct a decorator class of an already existing iterator class. A toy example may be:
#include<functional>
/**
* #brief Decorates an iterator to permit code injection before dereferencing
*/
template<class T>
struct IteratorDecorator : public T {
template<class V>
IteratorDecorator(T iterator, V f) : T(iterator) , m_callback(f) {}
typename T::value_type & operator*() {
m_callback();
return T::operator*();
}
private:
std::function<void()> m_callback;
};
/**
* #brief Convenience function just for type deduction
*/
template<class T, class V>
IteratorDecorator<T> decorate(T iterator, V v) {
return IteratorDecorator<T>(iterator,v);
}
This may be used in client code like this:
int main()
{
vector<int> ivec {1, 3, 5, 6};
try {
for_each(ivec.begin(),ivec.end(),[](int& x){ cout << x << endl; } );
for_each(decorate(ivec.begin(), [](){ cout << "decorated : "; }),
decorate(ivec.end() , [](){}),
[](int& x){ cout << x << endl; });
for_each(decorate(ivec.begin(), [](){ throw runtime_error("This one throws"); }),
decorate(ivec.end() , [](){}),
[](int& x){ cout << x << endl; } );
} catch( exception& e) {
cout << e.what() << endl;
}
return 0;
}
If you want to experiment with the code, you can find a working version here.
The easiest approach is to construct your iterators with a back-reference to the container they iterate over. Whenever you increment the container's end(), or decrement its begin(), or when you dereference anything outside the container's range, you throw an exception. Because the iterator has a reference to the container, you have all this information. The overhead is a simple reference (or pointer) per iterator, and a small amount of logic in the operator--, operator++ and operator*.
Microsoft use such an approach in their Checked Iterators which you can turn on when using their Standard Library. A sample implementation is given in SafeSTL. E.g. their vector<T> looks a bit like this:
template<class T>
class vector
{
public:
class iterator
{
public:
// regular iterator interface
private:
std::vector<T>* owner; // used by implementation to do checking
};
// rest of vector<T> interface
};
Or you could do the simplest possible thing and write a value type whose copy assignment operator throws (and/or move assignment operator, copy and move constructors,...).
Since you populate the container in the first place, you can even select which values throw, if you want. There's a lot less boilerplate than writing an iterator.
NB. I'm assuming you want to test your algorithm by forcing an exception. I think TemplateRex's suggestion is aimed more at iterators which catch accidental misuse at runtime. Feel free to clarify.
Sample implementations:
The simplest possible value type - it doesn't have any actual value, and always throws on copy or move:
struct TrivialThrowOnCopy {
TrivialThrowOnCopy() = default;
TrivialThrowOnCopy(TrivialThrowOnCopy const &) {
throw std::runtime_error("copy");
}
TrivialThrowOnCopy(TrivialThrowOnCopy&&) {
throw std::runtime_error("move");
}
};
Or you could have one where you explicitly tell each instance whether to throw or not:
struct ConfigurableThrowOnCopy {
bool should_throw_;
explicit ConfigurableThrowOnCopy(bool b = false) : should_throw_(b) {}
ConfigurableThrowOnCopy(ConfigurableThrowOnCopy const &other)
: should_throw_(other.should_throw_) {
if (should_throw_) throw std::runtime_error("copy");
}
ConfigurableThrowOnCopy(ConfigurableThrowOnCopy &&other)
: should_throw_(other.should_throw_) {
if (should_throw_) throw std::runtime_error("move");
}
};
or one where every _n_th copy throws:
struct CountingThrowOnCopy {
static unsigned counter;
// set CountingThrowOnCopy::counter = 5 to make the 5th copy throw
CountingThrowOnCopy() = default;
CountingThrowOnCopy(ConfigurableThrowOnCopy const &) {
if (!--counter) throw std::runtime_error("copy");
}
CountingThrowOnCopy(ConfigurableThrowOnCopy&&) {
if (!--counter) throw std::runtime_error("move");
}
};
or any of the above but wrapping an actual value:
template <typename T>
struct ConfigurableThrowOnCopyT {
T value_;
bool should_throw_;
explicit ConfigurableThrowOnCopyT(T const &t, bool b = false)
: value_(t), should_throw_(b) {}
ConfigurableThrowOnCopyT(ConfigurableThrowOnCopyT const &other)
: value_(other.value_), should_throw_(other.should_throw_) {
if (should_throw_) throw std::runtime_error("copy");
}
ConfigurableThrowOnCopyT(ConfigurableThrowOnCopyT &&other)
: value(std::move(other.value_)), should_throw_(other.should_throw_) {
if (should_throw_) throw std::runtime_error("move");
}
T& operator() { return value_; }
T const& operator() const { return value_; }
};
I need a shared_ptr like object, but which automatically creates a real object when I try to access its members.
For example, I have:
class Box
{
public:
unsigned int width;
unsigned int height;
Box(): width(50), height(100){}
};
std::vector< lazy<Box> > boxes;
boxes.resize(100);
// at this point boxes contain no any real Box object.
// But when I try to access box number 50, for example,
// it will be created.
std::cout << boxes[49].width;
// now vector contains one real box and 99 lazy boxes.
Is there some implementation, or I should to write my own?
It's very little effort to roll your own.
template<typename T>
class lazy {
public:
lazy() : child(0) {}
~lazy() { delete child; }
T &operator*() {
if (!child) child = new T;
return *child;
}
// might dereference NULL pointer if unset...
// but if this is const, what else can be done?
const T &operator*() const { return *child; }
T *operator->() { return &**this; }
const T *operator->() const { return &**this; }
private:
T *child;
};
// ...
cout << boxes[49]->width;
Using boost::optional, you can have such a thing:
// 100 lazy BigStuffs
std::vector< boost::optional<BigStuff> > v(100);
v[49] = some_big_stuff;
Will construct 100 lazy's and assign one real some_big_stuff to v[49]. boost::optional will use no heap memory, but use placement-new to create objects in a stack-allocated buffer. I would create a wrapper around boost::optional like this:
template<typename T>
struct LazyPtr {
T& operator*() { if(!opt) opt = T(); return *opt; }
T const& operator*() const { return *opt; }
T* operator->() { if(!opt) opt = T(); return &*opt; }
T const* operator->() const { return &*opt; }
private:
boost::optional<T> opt;
};
This now uses boost::optional for doing stuffs. It ought to support in-place construction like this one (example on op*):
T& operator*() { if(!opt) opt = boost::in_place(); return *opt; }
Which would not require any copy-ing. However, the current boost-manual does not include that assignment operator overload. The source does, however. I'm not sure whether this is just a defect in the manual or whether its documentation is intentionally left out. So i would use the safer way using a copy assignment using T().
I've never heard of such a thing, but then again there are lots of things I've never heard of. How would the "lazy pointer" put useful data into the instances of the underlying class?
Are you sure that a sparse matrix isn't what you're really looking for?
So far as I know, there's no existing implementation of this sort of thing. It wouldn't be hard to create one though.