Disclaimer: yes, I know about shared_ptr. But I still want to do this.
Also, I am aware I am not using locks nor atomics and so this is not thread safe.
Assume the following somewhat simple implementation of a 'smart' pointer. The semantics being that if you pass by value you increase the ref count and if you stick to references you have a 'weak' of sorts:
#pragma once
#include <iostream>
#include <cassert>
using std::cout;
template <class T>
class Ptr {
private:
T* ptr;
int* refCount;
public:
Ptr(T* ptr) {
assert(ptr);
this->ptr = ptr;
this->refCount = new int(1);
}
Ptr(Ptr& from) {
swap(*this, from);
}
Ptr(Ptr&& from) {
swap(*this, from, false);
}
Ptr& operator=(const Ptr& from) {
swap(*this, from);
return *this;
}
~Ptr() {
if (*refCount >= 1) {
(*refCount)--;
cout << "\n Ptr destructor: new ref count: " << *refCount;
if (*refCount == 0) {
delete ptr;
ptr = nullptr;
}
}
}
operator bool() {
return (*refCount >= 1);
}
T* operator->() {
assert(*refCount >= 1);
return ptr;
}
int referenceCount() {
return *refCount;
}
private:
template <class T>
void swap(Ptr<T>& to, Ptr<T>& from, bool isCopy = true) {
assert((*from.refCount) >= 1);
to.ptr = from.ptr;
to.refCount = from.refCount;
if (isCopy) {
(*to.refCount)++;
}
else {
from.ptr = nullptr;
}
}
};
class A {
public:
A() = default;
~A() {
cout << "\n dealloc:" << this;
}
void doSomething() {
}
};
void Test() {
{
Ptr<A> p1(new A);
cout << "\ncheckpoint - refCount (should be 1): " << p1.referenceCount();
Ptr<A> p2 = p1;
cout << "\ncheckpoint - refCount (should be 2): " << p1.referenceCount();
Ptr<A>& p3 = p1;
cout << "\ncheckpoint - refCount (should be 2): " << p1.referenceCount();
Ptr<A> p4 = std::move(p1);
cout << "\ncheckpoint - refCount (should be 2): " << p4.referenceCount();
Ptr<A> p5 = p4;
cout << "\ncheckpoint - refCount (should be 3): " << p5.referenceCount();
}
cout << "\nend";
}
I get the following output which is as expected:
checkpoint - refCount (should be 1): 1
checkpoint - refCount (should be 2): 2
checkpoint - refCount (should be 2): 2
checkpoint - refCount (should be 2): 2
checkpoint - refCount (should be 3): 3
Ptr destructor: new ref count: 2
Ptr destructor: new ref count: 1
Ptr destructor: new ref count: 0
dealloc:00C3D060
But there is one big problem.
Assume I had kept any of those references (could have been a pointer for that matter -- any handle that acts as a weak ref), and the last strong ref goes out of scope. The original pointer is now null and the smart pointer's counter (which I am leaking), would still allow any weak handles to behave appropriately since it would still hold a valid value of 0.
But had I deleted the counter pointer, any references left would eventually point to other data if that memory location got used for something else, which could include any number other than 0.
So I'm thinking I might need to crate a static pointer to a value of 0 and instead use pointers to pointers for the counter? That way whichever strong ref deletes the pointer could also point all counters to the static 0?
I'm kind of confused about it. Especially since I was looking at the source code of a rendering engine and their shared ptr class is very similar to the above code.
Related
#include <memory> // for std::unique_ptr and std::make_unique
#include <iostream>
class Fraction
{
private:
int m_numerator;
int m_denominator;
public:
Fraction(int numerator, int denominator) :
m_numerator{ numerator }, m_denominator{ denominator }
{
}
friend std::ostream& operator<<(std::ostream& out, const Fraction &f1)
{
out << f1.m_numerator << "/" << f1.m_denominator;
return out;
}
friend operator=(const Fraction &f1,const int numerator,const int denominator){
f1.m_numerator=numerator;
f1.m_denominator=denominator;
}
};
int main()
{
// Create a single dynamically allocated Fraction with numerator 3 and denominator 5
std::unique_ptr<Fraction> f1{ std::make_unique<Fraction>(3, 5) };
std::cout << *f1 << '\n';
// Create a dynamically allocated array of Fractions of length 4
// We can also use automatic type deduction to good effect here
auto f2{ std::make_unique<Fraction[]>(4) };
f2[0]=(3,5);
f2[1]=(67,82,5,543345);
std::cout << f2[0] << '\n';
std::cout << f2[1] << '\n';
return 0;
}
First, operator= can be implemented only as member function, not free function. So your approach is just wrong. Second, overloaded operator= can accept only one parameter. The closest thing you want, can be achived by passing initializer_list as this parameter:
Fraction& operator=(std::initializer_list<int> il){
// some code validating size of il here
this->m_numerator=*il.begin();
this->m_denominator = *(il.begin()+1);
return *this;
}
the use looks like:
f2[0]={3,5};
f2[1]={67,84};
Full demo
I am still new to c++, so bear with me.
I was trying to learn more about how std::move works and I saw an example where they used std::move to move the string to a different function and then showed using std::cout that no string remained. I thought cool, let's see if I can make my own class and do the same:
#include <iostream>
#include <string>
class integer
{
private:
int *m_i;
public:
integer(int i=0) : m_i(new int{i})
{
std::cout << "Calling Constructor\n";
}
~integer()
{
if(m_i != nullptr) {
std::cout << "Deleting integer\n";
delete m_i;
m_i = nullptr;
}
}
integer(integer&& i) : m_i(nullptr) // move constructor
{
std::cout << "Move Constructor\n";
m_i = i.m_i;
i.m_i = nullptr;
}
integer(const integer& i) : m_i(new int) { // copy constructor
std::cout << "Copy Constructor\n";
*m_i = *(i.m_i);
}
//*
integer& operator=(integer&& i) { // move assignment
std::cout << "Move Assignment\n";
if(&i != this) {
delete m_i;
m_i = i.m_i;
i.m_i = nullptr;
}
return *this;
}
integer& operator=(const integer &i) { // copy assignment
std::cout << "Copy Assignment\n";
if(&i != this) {
m_i = new int;
*m_i = *(i.m_i);
}
return *this;
}
int& operator*() const { return *m_i; }
int* operator->() const { return m_i; }
bool empty() const noexcept {
if(m_i == nullptr) return true;
return false;
}
friend std::ostream& operator<<(std::ostream &out, const integer i) {
if(i.empty()) {
std::cout << "During overload, i is empty\n";
return out;
}
out << *(i.m_i);
return out;
}
};
void g(integer i) { std::cout << "G-wiz - "; std::cout << "The g value is " << i << '\n'; }
void g(std::string s) { std::cout << "The g value is " << s << '\n'; }
int main()
{
std::string s("Hello");
std::cout << "Now for string\n";
g(std::move(s));
if(s.empty()) std::cout << "s is empty\n";
g(s);
std::cout << "\nNow for integer\n";
integer i = 77;
if(!i.empty()) std::cout << "i is " << i << '\n';
else std::cout << "i is empty\n";
g(i);
std::cout << "Move it\n";
g(std::move(i)); // rvalue ref called
if(!i.empty()) std::cout << "i is " << i << '\n';
else std::cout << "i is empty\n";
g(i);
return 0;
}
And this is my output:
Now for string
The g value is Hello
s is empty
The g value is
Now for integer
Calling Constructor
Copy Constructor
i is 77
Deleting integer
Copy Constructor
G-wiz - Copy Constructor
The g value is 77
Deleting integer
Deleting integer
Move it
Move Constructor
G-wiz - Copy Constructor
The g value is 77
Deleting integer
Deleting integer
i is empty
Copy Constructor
Process returned 255 (0xFF) execution time : 7.633 s
Press any key to continue.
As you can see, it crashes when it enters g the second time, never even getting to the operator<<() function. How is it that the empty std::string s can be passed to g where my empty integer i crashes the program?
Edit: Fixed new int vs. new int[] error. Thanks n.m.
Your "empty integer" crashes the program because it contains a null pointer. You are trying to dereference it when you use it at the right hand side of the assignment.
An empty string is a normal usable string. There are no unchecked null pointer dereferences in the std::string code.
You have to ensure that the empty state of your object is a usable one. Start with defining a default constructor. Does it make sense for your class? If not, then move semantic probably doesn't either. If yes, a moved-from object in the move constructor should probably end up in the same state as a default-constructed object. A move assignment can act as a swap operation, so there the right-hand-side may end up either empty or not.
If you don't want to define a usable empty state for your class, and still want move semantics, you simply cannot use an object after it has been moved from. You still need to make sure that an empty object is destructible.
I have K objects (K is small, e.g. 2 or 5) and I need to iterate over them N times in random order where N may be large. I need to iterate in a foreach loop and for this I should provide an iterator.
So far I created a std::vector of my K objects copied accordingly, so the size of vector is N and now I use begin() and end() provided by that vector. I use std::shuffle() to randomize the vector and this takes up to 20% of running time. I think it would be better (and more elegant, anyways) to write a custom iterator that returns one of my object in random order without creating the helping vector of size N. But how to do this?
It is obvious that your iterator must:
Store pointer to original vector or array: m_pSource
Store the count of requests (to be able to stop): m_nOutputCount
Use random number generator (see random): m_generator
Some iterator must be treated as end iterator: m_nOutputCount == 0
I've made an example for type int:
#include <iostream>
#include <random>
class RandomIterator: public std::iterator<std::forward_iterator_tag, int>
{
public:
//Creates "end" iterator
RandomIterator() : m_pSource(nullptr), m_nOutputCount(0), m_nCurValue(0) {}
//Creates random "start" iterator
RandomIterator(const std::vector<int> &source, int nOutputCount) :
m_pSource(&source), m_nOutputCount(nOutputCount + 1),
m_distribution(0, source.size() - 1)
{
operator++(); //make new random value
}
int operator* () const
{
return m_nCurValue;
}
RandomIterator operator++()
{
if (m_nOutputCount == 0)
return *this;
--m_nOutputCount;
static std::default_random_engine generator;
static bool bWasGeneratorInitialized = false;
if (!bWasGeneratorInitialized)
{
std::random_device rd; //expensive calls
generator.seed(rd());
bWasGeneratorInitialized = true;
}
m_nCurValue = m_pSource->at(m_distribution(generator));
return *this;
}
RandomIterator operator++(int)
{ //postincrement
RandomIterator tmp = *this;
++*this;
return tmp;
}
int operator== (const RandomIterator& other) const
{
if (other.m_nOutputCount == 0)
return m_nOutputCount == 0; //"end" iterator
return m_pSource == other.m_pSource;
}
int operator!= (const RandomIterator& other) const
{
return !(*this == other);
}
private:
const std::vector<int> *m_pSource;
int m_nOutputCount;
int m_nCurValue;
std::uniform_int_distribution<std::vector<int>::size_type> m_distribution;
};
int main()
{
std::vector<int> arrTest{ 1, 2, 3, 4, 5 };
std::cout << "Original =";
for (auto it = arrTest.cbegin(); it != arrTest.cend(); ++it)
std::cout << " " << *it;
std::cout << std::endl;
RandomIterator rndEnd;
std::cout << "Random =";
for (RandomIterator it(arrTest, 15); it != rndEnd; ++it)
std::cout << " " << *it;
std::cout << std::endl;
}
The output is:
Original = 1 2 3 4 5
Random = 1 4 1 3 2 4 5 4 2 3 4 3 1 3 4
You can easily convert it into a template. And make it to accept any random access iterator.
I just want to increment Dmitriy answer, because reading your question, it seems that you want that every time that you iterate your newly-created-and-shuffled collection the items should not repeat and Dmitryi´s answer does have repetition. So both iterators are useful.
template <typename T>
struct RandomIterator : public std::iterator<std::forward_iterator_tag, typename T::value_type>
{
RandomIterator() : Data(nullptr)
{
}
template <typename G>
RandomIterator(const T &source, G& g) : Data(&source)
{
Order = std::vector<int>(source.size());
std::iota(begin(Order), end(Order), 0);
std::shuffle(begin(Order), end(Order), g);
OrderIterator = begin(Order);
OrderIteratorEnd = end(Order);
}
const typename T::value_type& operator* () const noexcept
{
return (*Data)[*OrderIterator];
}
RandomIterator<T>& operator++() noexcept
{
++OrderIterator;
return *this;
}
int operator== (const RandomIterator<T>& other) const noexcept
{
if (Data == nullptr && other.Data == nullptr)
{
return 1;
}
else if ((OrderIterator == OrderIteratorEnd) && (other.Data == nullptr))
{
return 1;
}
return 0;
}
int operator!= (const RandomIterator<T>& other) const noexcept
{
return !(*this == other);
}
private:
const T *Data;
std::vector<int> Order;
std::vector<int>::iterator OrderIterator;
std::vector<int>::iterator OrderIteratorEnd;
};
template <typename T, typename G>
RandomIterator<T> random_begin(const T& v, G& g) noexcept
{
return RandomIterator<T>(v, g);
}
template <typename T>
RandomIterator<T> random_end(const T& v) noexcept
{
return RandomIterator<T>();
}
whole code at
http://coliru.stacked-crooked.com/a/df6ce482bbcbafcf or
https://github.com/xunilrj/sandbox/blob/master/sources/random_iterator/source/random_iterator.cpp
Implementing custom iterators can be very tricky so I tried to follow some tutorials, but please let me know if something have passed:
http://web.stanford.edu/class/cs107l/handouts/04-Custom-Iterators.pdf
https://codereview.stackexchange.com/questions/74609/custom-iterator-for-a-linked-list-class
Operator overloading
I think that the performance is satisfactory:
On the Coliru:
<size>:<time for 10 iterations>
1:0.000126582
10:3.5179e-05
100:0.000185914
1000:0.00160409
10000:0.0161338
100000:0.180089
1000000:2.28161
Off course it has the price to allocate a whole vector with the orders, that is the same size of the original vector.
An improvement would be to pre-allocate the Order vector if for some reason you have to random iterate very often and allow the iterator to use this pre-allocated vector, or some form of reset() in the iterator.
How to execute the body of the loop for every member of some type? I know I could repeat the body of the loop for the maxval after the loop, but it would be duplicating code which is bad. I also could make a function out of the body but it looks wrong to me too because functions should be small and simple and the body of the loop is huge.
const auto minval = std::numeric_limits<T>::min();
const auto maxval = std::numeric_limits<T>::max();
for (auto i = minval; i < maxval; ++i) {
// huge body of the loop
}
It is as simple as stopping after you process the last item:
auto i = minval;
while(1) {
// do all the work for `i`
if (i == maxval) break;
++i;
}
One can also move the increment to the top of the loop, provided it is skipped on the first pass:
i = minval;
switch (1) {
case 0:
do {
++i;
case 1:
// processing for `i`
} while (i != maxval);
}
The latter version translates to efficient machine code a little more directly, as each loop iteration has only a single conditional branch, and there is a single unconditional branch, while in the first there is a conditional branch plus an unconditional branch which both repeat every iteration.
Neither version increments the ultimate value, which might be undefined behavior.
You have to maintain a bit of additional state to indicate whether you've seen the last value or not. Here's a simple example that could be moved to a more idiomatic iterator style without too much work:
#include <iostream>
#include <limits>
using namespace std;
template <typename T>
class allvalues
{
public:
allvalues() = default;
T next()
{
if (done) throw std::runtime_error("Attempt to go beyond end of range");
T v = val;
done = v == std::numeric_limits<T>::max();
if (!done) ++val;
return v;
}
bool isDone() { return done; }
private:
T val = std::numeric_limits<T>::min();
bool done = false;
};
int main() {
allvalues<char> range;
while (!range.isDone())
{
std::cout << "Value = " << (int)range.next() << std::endl;
}
allvalues<unsigned char> urange;
while (!urange.isDone())
{
std::cout << "Value = " << (unsigned int)urange.next() << std::endl;
}
std::cout << "That's it!" << std::endl;
}
I have been searching for a while but I couldn't find clear explanation for my doubts.
Mainly:
struct foo
{
foo(int n=0) : m_n(n) {}
int m_n;
};
std::vector<foo> vec;
vec.push_back(100);
vec.push_back(55);
vec.push_back(6);
std::cout << vec.data() << std::endl; //0x1aca010
std::cout << vec.capacity() << std::endl; //4
vec.push_back(6);
vec.push_back(6);
std::cout << vec.data() << std::endl; //0x1aca050 *
std::cout << vec.capacity(); //8
*As I understand a vector is an dynamic array which contains data in one continuous block of memory. When we resize it and there is out of space for more elements, new block of memory is being allocated and all elements are copied to that one. Does it work the same with respect to the move semantic in c++11? It's not a list so pointers can't be just "swaped".
Why do you think pointers can't just be "swapped"? Let me show you a possible implementation >o<
template <typename T>
class vector
{
private:
T *mem;
// ...
public:
// ...
vector(vector &&rhs)
: vector() // delegate constructor
{
rhs.swap(*this);
}
vector &operator =(vector &&rhs)
{
rhs.swap(*this);
rhs.clear();
rhs.shrink_to_fit();
return *this;
}
void swap(vector &obj)
{
using std::swap;
swap(mem, obj.mem);
// ...
}
// ...
};
However, if you want to use a different allocator from an original vector (i.e. to use the sixth constructor of this page), you should allocate new memory and copy data into it, not just swap pointers.