Suppose I have a class called Entry:
template <typename K, typename V>
class Entry {
public:
Entry(K const &key, V const &val, size_t const hash_val) :
key(key), val(val), hash_val(hash_val), empty(false){
}
K getKey() const {
return key;
}
V getValue() const {
return val;
}
size_t getHash() const {
return hash_val;
}
bool isEmpty() const{
return empty;
}
private:
// key-value pair
K key;
V val;
// Store hash for reallocation
size_t hash_val;
// Store empty state
bool empty;
};
Then I create an array of objects
Entry<K, V>** entries = new Entry<K, V> *[100];
If I call entries[0]->isEmpty(), I get a segmentation fault. This makes sense to me, since I haven't actually instantiated a new object in memory. However, I want to be able to check whether a slot in the array actually points to a valid object. Currently, I've been setting each pointer to nullptr so I can check for equality later, but I was wondering if there was a better way.
You want optional. It's always either a valid object, or in an "empty" state.
#include <cstdio>
#include <optional>
#include <vector>
struct Foo {
int bar;
};
int main() {
std::vector<std::optional<Foo>> vfoo{
Foo{1}, std::nullopt, Foo{2}, Foo{3}, std::nullopt,
};
for (auto const& foo : vfoo) {
if (!foo)
std::puts("Not Initialized");
else
std::printf("Foo{%d}\n", foo->bar);
}
}
There is no way to check if a pointer has been initialized, because reading from an unitialized pointer is undefined behavior:
int* p;
if (p == something) ... // undefined behavior
You can initialize the pointer with nullptr and check for that:
int* p = nullptr;
if (p == nullptr) ...
However, then you are initializing the pointer.
For a dynamic array of Entry<K, V>* you can use a std::vector<Entry<K,V>*>. A container that can be used analogous to an array with empty slots is a std::unordered_map:
std::unordered_map<size_t,Entry<K,V>*> map;
Entry<K,V>* ptr = get_pointer_from_somewhere();
size_t index = 42;
if ( map.find(index) == map.end() ) {
// pointer was not initialized (actually pointer is not yet in the map)
map.insert( { index, ptr }); // now it is
}
Actually insert alone will tell you already if the element with key index was present in the map before.
Related
Why the Range-based for loop does not work with pointer of arrays?
auto pCollection = new int[3] { 0,1,2 };
// error C3312: no callable 'begin' function found for type 'int *'
for (auto value : pCollection)
{
std::cout << value << std::endl;
}
delete[] pCollection;
but can be used on arrays:
int collection[3]{ 0,1,2 };
for (auto value : collection)
{
std::cout << value << std::endl;
}
A pointer is not an array. There is no way to know, from the pointer alone, how many elements there may or may not be at the location that a pointer points to.
Suppose your dynamically-allocated array is returned from a function:
int *pCollection = getCollection();
How will you find the end of the array? Well, you can't -- that pointer only points to the first element, it does not bundle any size information. In fact, it could point to a single int allocated with new and you wouldn't know either. Pointers just aren't containers -- only pointers.
auto pCollection = new int[3] { 0,1,2 };
this isn't an int[3]. It is an int* that points to a buffer of 3 int.
The type carries no information about its size.
int collection[3]{ 0,1,2 };
this is an int[3]. Its type says how big it is.
Here we create two different sized new'd arrays
auto pCollection = (rand()%2)?new int[3] { 0,1,2 }:new int[5]{1,2,3,4,5};
and store a pointer to one or the other. The type of pCollection doesn't know how big it is. There is no way in C++ to get at its size, and as destruction is trivial, it would be acceptable for the OS to give us enough room for 8 ints and say "whatever" about the extra space. So even accessing low level memory APIs may not tell us how large it is.
Witn an actual int[3],
for (auto value : collection) {
std::cout << value << std::endl;
}
this statement can use the type of collection to know how many elements to visit. std::begin and std::end are overloaded to do the right thing, and for(:) loops are similarly specified to do the right thing.
With an int*, there is no type information about its length stored.
We can store it ourselves. And provide a type that knows it.
Here is a quick one:
template<class It, class R=void>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
range_t(It s, It f):b(std::move(s)), e(std::move(f)) {}
range_t() noexcept(noexcept(It{})) :range_t({},{}) {}
range_t(range_t const&)=default;
range_t(range_t &&)=default;
range_t& operator=(range_t const&)=default;
range_t& operator=(range_t &&)=default;
~range_t()=default;
decltype(auto) front() const { return *begin(); }
decltype(auto) back() const { return *std::prev(end()); }
using own_type = std::conditional_t<
std::is_same<R,void>::value,
range_t,
R
>;
own_type without_front( std::size_t N=1 ) const {
return {std::next(begin(), N), end()};
}
own_type without_back( std::size_t N=1 ) const {
return {begin(), std::prev(end(),N)};
}
std::size_t size() const {
return std::distance( begin(), end() );
}
bool empty() const {
return begin()==end();
}
};
template<class T>
struct span_t:range_t<T*, span_t<T>> {
span_t(T* s, T* f):range_t<T*>(s, f) {}
span_t(T* s, std::size_t l):span_t(s, s+l) {}
T& operator[](std::size_t n)const{ return begin()[n]; }
span_t( range_t<T*> o ):range_t<T*>(o) {}
span_t( span_t const& ) = default;
span_t& operator=( span_t const& ) = default;
span_t() noexcept(true) : span_t(nullptr, nullptr) {}
};
template<class T>
span_t<T> span(T* s, T* f){ return {s,f}; }
template<class T>
span_t<T> span(T* s, std::size_t length){ return {s,length}; }
so now we can do this:
auto pCollection = new int[3] { 0,1,2 };
for (auto value : span(pCollection,3)) {
std::cout << value << std::endl;
}
delete[] pCollection;
and bob is your uncle.
Note GSL has a better more complete span<T> type.
To turn it into range use
boost::make_iterator_range(pCollection, pCollection+3)
I have a big vector container that holds around 300.000 object. Also I have pointers to these objects.
Are there any fast way to get index of object in vector with using pointer?
Since vectors are organized sequentially, you can get an index by subtracting pointer to initial element from the pointer to element in question:
std::vector<MyObject> vect;
MyObject *ptrX = ... // Pointer to element in question
ptrdiff_t index = ptrX - &vect[0];
Iterator header should be useful in that case.
Let's assume you have something like:
using Vector = std::vector<Foo>;
using Iterator = Vector::iterator;
Vector big_vector;
And now your have an iterator to an object:
Iterator p_obj = get_Theobj(big_vector);
The the index could be easily get with distance:
auto index = std::distance(big_vector.begin(), p_obj);
// Note: index's type is a `difference_type` aka ptrdiff_t (usually signed integer).
The powerful of using that approach is the versatility. Indeed, it works with "C-like vector", std::array, std::list, as well.
You may use std::distance
std::vector<Object> objects = /*..*/;
const Object *p = /* object[i] */;
std::ptrdiff_t index = std::distance(objects.data(), p);
// Now index == i.
Plenty of good answers here. Combining them together, here's a little library suite which allows computation of the index of an item by either pointer or reference.
As an added bonus, the caller may optionally supply a policy object, to be enacted if the element is not in the container.
#include <stdexcept>
#include <cassert>
#include <vector>
struct exception_policy
{
[[noreturn]]
std::size_t out_of_range() const
{
throw std::out_of_range("index_of_element");
}
};
struct assertion_policy
{
std::size_t out_of_range() const
{
assert(!"out of range");
return _fallback.out_of_range();
}
exception_policy _fallback {};
};
struct zero_policy
{
std::size_t out_of_range() const
{
return 0;
}
};
template<class T, class A, class Policy = exception_policy>
std::size_t index_of_element(std::vector<T, A> const& vec,
typename std::vector<T, A>::const_pointer pitem,
Policy policy = Policy{})
{
auto pbegin = vec.data();
auto pend = pbegin + vec.size();
if (pitem < pbegin or pitem >= pend)
{
return policy.out_of_range();
}
else
{
return std::distance(pbegin, pitem);
}
}
template<class T, class A, class Policy = exception_policy>
std::size_t index_of_element(std::vector<T, A> const& vec,
typename std::vector<T, A>::const_reference item, Policy policy = Policy{})
{
return index_of_element(vec, std::addressof(item), policy);
}
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8 };
auto px = std::addressof(v[5]);
auto& rx = *px;
try {
// use default policy of throwing out_of_range...
auto i = index_of_element(v, rx);
assert(i == 5);
}
catch(...)
{
assert(!"should not throw");
}
try {
auto i = index_of_element(v, px);
assert(i == 5);
}
catch(...)
{
assert(!"should not throw");
}
auto py = v.data() + 1000; // out of bounds
try {
auto i = index_of_element(v, py);
assert(!"should have thrown");
}
catch(std::out_of_range const& e)
{
// success
}
catch(...)
{
assert(!"should not throw this");
}
// specify a custom policy
auto i = index_of_element(v, ry, zero_policy());
assert(i == 0);
}
int getIndex(Object* pObject) {return pObject - &(my_vewctor[0]);}
Assuming C++11 at least:
You have some class Myclass; (hopefully a rather small one, since you have many instances of it).
You have some variable std::vector<Myclass> bigvec; and it is big enough so could have about half a million objects.
You have some valid pointer Myclass* ptr; and it could point inside an object from bigvec.
You might get its index in bigvec in int ix; (or better yet size_t ix;) using
if (ptr >= bigvec.data() && ptr < bigvec.data() + bigvec.size())
ix = ptr - bigvec.data();
However, be aware that you could have made copies of Myclass (e.g. thru assignment, passing by value some argument, etc...), and then a pointer to such a copy won't be in bigvec
I'd like to find a value in unordered_set, but failed:
typedef std::shared_ptr<int> IntPtr;
std::unordered_set<IntPtr> s;
s.insert(std::make_shared<int>(42));
bool found = s.find(std::make_shared<int>(42)) != s.end();
cout<<std::boolalpha<<found<<endl; // false
Had tried following but still not working.
namespace std {
template <> struct hash<IntPtr> {
size_t operator()(const IntPtr& x) const noexcept {
return std::hash<int>()(*x);
}
};
}
Any idea how to make it works?
You stored a pointer to an integer. When you look up items in the set, you're not comparing the (pointed-to) integer, but the pointer itself.
When you allocate a new pointer to a new integer object for the search, it won't compare equal, because it's a different integer object (even though it stores the same value).
Your options are:
don't store pointers to integers in your set, just store the integers directly.
Then, your key is 42, and searching for 42 will find it, because the integers are compared by value
store pointers and use a custom hash and comparator to compare the pointed-at integers instead of the pointers.
You shouldn't (try to) pollute std namespace with your hash specialization, and it's not sufficient anyway (the hash is used for bucket lookup, but keys are still compared with KeyEqual inside the bucket). Just specify them for your container.
Example code for #2:
#include <cassert>
#include <memory>
#include <unordered_set>
struct Deref {
struct Hash {
template <typename T>
std::size_t operator() (std::shared_ptr<T> const &p) const {
return std::hash<T>()(*p);
}
};
struct Compare {
template <typename T>
size_t operator() (std::shared_ptr<T> const &a,
std::shared_ptr<T> const &b) const {
return *a == *b;
}
};
};
int main() {
std::unordered_set<std::shared_ptr<int>> sp;
auto p = std::make_shared<int>(42);
sp.insert(p);
assert(sp.find(p) != sp.end()); // same pointer works
assert(sp.find(std::make_shared<int>(42)) == sp.end()); // same value doesn't
// with the correct hash & key comparison, both work
std::unordered_set<std::shared_ptr<int>, Deref::Hash, Deref::Compare> spd;
spd.insert(p);
assert(spd.find(p) != spd.end());
assert(spd.find(std::make_shared<int>(42)) != spd.end());
}
According to here:
Note that the comparison operators for shared_ptr simply compare pointer values; the actual objects pointed to are not compared.
So found will be true only if shared_ptr points to same object:
typedef std::shared_ptr<int> IntPtr;
std::unordered_set<IntPtr> s;
IntPtr p = std::make_shared<int>(42);
s.insert(p);
bool found = s.find(p) != s.end();
cout<<std::boolalpha<<found<<endl; // true
This is very similar to auto_ptr for arrays. However, my wrinkle is I don't want an initialized array, which is what a vector would provide (the const T& value = T()):
explicit vector(size_type count,
const T& value = T(),
const Allocator& alloc = Allocator());
I don't want the array initialized because its a large array and the values will be immediately discarded.
I'm currently hacking it with the following, but it feels like something is wrong with it:
//! deletes an array on the heap.
template <class T>
class AutoCleanup
{
public:
AutoCleanup(T*& ptr) : m_ptr(ptr) { }
~AutoCleanup() { if (m_ptr) { delete[] m_ptr; m_ptr = NULL; }}
private:
T*& m_ptr;
};
And:
// AutoCleanup due to Enterprise Analysis finding on the stack based array.
byte* plaintext = new byte[20480];
AutoCleanup<byte> cleanup(plaintext);
// Do something that could throw...
What does C++ provide for an array of a POD type that is uninitialized and properly deleted?
The project is C++03, and it has no external dependencies, like Boost.
From your question, it's not easy to interpret what you actually need. But I guess you want an array which is stack-guarded (i.e. lifetime bound to the stack), heap-allocated, uninitialized, dynamically or statically sized, and compatible with pre-C++11 compilers.
auto_ptr can't handle arrays (because it doesn't call delete[] in its destructor, but rather delete).
Instead, I would use boost::scoped_array together with new[] (which doesn't initialize POD types afaik).
boost::scoped_array<MyPodType> a(new MyPodType[20480]);
If you don't want to use boost, you can reimplement scoped_array pretty easily by pasting the code together which this class includes from the boost library:
#include <cassert>
#include <cstddef>
// From <boost/checked_delete.hpp>:
template<class T>
inline void checked_array_delete(T * x)
{
typedef char type_must_be_complete[sizeof(T) ? 1 : -1];
(void) sizeof(type_must_be_complete);
delete [] x;
}
// From <boost/smartptr/scoped_array.hpp>:
template<class T>
class scoped_array
{
private:
T * px;
// Make this smart pointer non-copyable
scoped_array(scoped_array const &);
scoped_array & operator=(scoped_array const &);
typedef scoped_array<T> this_type;
public:
typedef T element_type;
explicit scoped_array(T * p = 0) : px(p) { }
~scoped_array() {
checked_array_delete(px);
}
void reset(T * p = 0) {
assert(p == 0 || p != px); // catch self-reset errors
this_type(p).swap(*this);
}
T & operator[](std::ptrdiff_t i) const {
assert(px != 0);
assert(i >= 0);
return px[i];
}
T * get() const {
return px;
}
operator bool () const {
return px != 0;
}
bool operator ! () const {
return px == 0;
}
void swap(scoped_array & b) {
T * tmp = b.px;
b.px = px;
px = tmp;
}
};
I have a std::set<Foo>, and I'd like to update some value of
an existing element therein. Note that the value I'm updating does not change the order in the set:
#include <iostream>
#include <set>
#include <utility>
struct Foo {
Foo(int i, int j) : id(i), val(j) {}
int id;
int val;
bool operator<(const Foo& other) const {
return id < other.id;
}
};
typedef std::set<Foo> Set;
void update(Set& s, Foo f) {
std::pair<Set::iterator, bool> p = s.insert(f);
bool alreadyThere = p.second;
if (alreadyThere)
p.first->val += f.val; // error: assignment of data-member
// ‘Foo::val’ in read-only structure
}
int main(int argc, char** argv){
Set s;
update(s, Foo(1, 10));
update(s, Foo(1, 5));
// Now there should be one Foo object with val==15 in the set.
return 0;
}
Is there any concise way to do this? Or do I have to check if the element is already there, and if so, remove it, add the value and re-insert?
Since val is not involved in comparison, it could be declared mutable
struct Foo {
Foo(int i, int j) : id(i), val(j) {}
int id;
mutable int val;
bool operator<(const Foo& other) const {
return id < other.id;
}
};
This implies that the value of val may change in a logically-const Foo, which means that it shouldn't affect other comparison operators etc.
Or you could just remove and insert, that takes O(1) additional time (compared to accessing and modifying) if insertion uses the position just before just after the old one as the hint.
Something like:
bool alreadyThere = !p.second; // you forgot the !
if (alreadyThere)
{
Set::iterator hint = p.first;
hint++;
s.erase(p.first);
s.insert(hint, f);
}
Don't try to solve this problem by working around the const-ness of items in a set. Instead, why not use map, which already expresses the key-value relationship you are modeling and provides easy ways to update existing elements.
Make val mutable as:
mutable int val;
Now you can change/modify/mutate val even if foo is const:
void f(const Foo & foo)
{
foo.val = 10; //ok
foo.id = 11; //compilation error - id is not mutable.
}
By the way, from your code, you seem to think that if p.second is true, then the value already existed in the set, and therefore you update the associated value. I think, you got it wrong. It is in fact other way round. The doc at cpluscplus says,
The pair::second element in the pair is set to true if a new element was inserted or false if an element with the same value existed.
which is correct, in my opinion.
However, if you use std::map, your solution would be straightforward:
void update(std::map<int,int> & m, std::pair<int,int> value)
{
m[value.first] += value.second;
}
What does this code do? m[value.first] creates a new entry if the key doesn't exist in the map, and value of the new entry is default value of int which is zero. So it adds value.second to zero. Or else if the key exists, then it simply adds value.second to it. That is, the above code is equivalent to this:
void update(std::map<int,int> & m, std::pair<int,int> value)
{
std::map<int,int>::iterator it = m.find(value);
if ( it != m.end()) //found or not?
it.second += value; //add if found
else
{
m.insert(value); //insert if not found
}
}
But this is too much, isn't it? It's performance is not good. The earlier one is more concise and very performant.
If you know what you're doing (the set elements are not const per se and you're not changing members involved in comparison), then you can just cast away const-ness:
void update(Set& s, Foo f) {
std::pair<Set::iterator, bool> p = s.insert(f);
bool alreadyThere = !p.second;
if (alreadyThere)
{
Foo & item = const_cast<Foo&>(*p.first);
item.val += f.val;
}
}
Instead of separate hint, use the erase's return value for the next iterator position
bool alreadyThere = !p.second;
if (alreadyThere)
{
auto nit = s.erase(p.first);
s.insert(nit, f);
}
you can use MAP witch has very fast access to your element if you have KEY . in this case i think using MAP would be better way to achieve fastest speed . STD::MAP