#include<iostream>
#include<set>
template <typename T>
/* Simple smart pointer class */
class SmartPtr
{
T *ptr;
public:
explicit SmartPtr(T *p = NULL) { ptr = p; }
~SmartPtr() { delete(ptr); }
T & operator * () { return *ptr; }
T * operator -> () { return ptr; }
};
class simple {
private:
int x;
public:
simple(int y = 0) :x(y) {}
int getX() { return x; }
};
typedef SmartPtr<simple> simplePtr;
int main() {
std::set<simplePtr> st;
simplePtr p1 = simplePtr(new simple(5));
simplePtr p2 = simplePtr(new simple(5));
simplePtr p3 = simplePtr(new simple(5));
simplePtr p4 = simplePtr(new simple(5));
std::cout << p1->getX(); <-- working fine
st.insert(p1);
st.insert(p2);
st.insert(p3);
st.insert(p4);
for (std::set<simplePtr>::iterator it = st.begin(); it != st.end(); ++it)
{
std::cout << it->getX(); // Not working??
}
}
Compilation is failed with error in Visual Studio 2013:
Error C2039 getX: is not a member of SmartPtr<simple>
On linux:
error: ‘const class SmartPtr<simple>’ has no member named ‘getX’
Is this a problem with iterator??
You can think of it->getX() as a syntactic sugar for (*it).getX(). [In principle, a class can overload the -> and * (dereferencing) operators inconsistently, but std::set<T>::iterator, unsurprisingly, doesn't break that convention]. So, in your case, *it is dereferenced to an lvalue of type const SmartPtr<simple>&, and the .getX() applied to it fails, because SmartPtr doesn't have a getX() method. Since, instead you mean to access the object that the obtained SmartPtr points to, you must add one more level of dereferencing:
Correction 1
Replace it->getX() with (**it).getX() or (*it)->getX().
There is still another problem, though - *it results in a const SmartPtr (yes, std::set's non-constant iterator doesn't provide write access to the container's elements, otherwise you could break correct ordering of elements in the container). But both -> and * (dereferencing) operators in SmartPtr are defined in such a way that they can be invoked only on non-const objects. To fix that, you must make those two functions const:
Correction 2 (in SmartPtr<T>)
// vvvvv
T & operator * () const { return *ptr; }
T * operator -> () const { return ptr; }
// ^^^^^
After you make this second correction, you can replace your old-style for-loop with a range-for loop:
for (const simplePtr& p : st)
{
std::cout << p->getX();
}
Still, your program will not compile - SmartPtr<T> objects cannot be put in an std::set since they are not comparable. Fix that by defining operator<():
Correction 3
Add to SmartPtr<T>:
bool operator<(const SmartPtr& other) const { return ptr < other.ptr; }
At this point your code will compile but chances are high that it will not work correctly. The reason is that the copy-semantics of SmartPtr<T> is left to compiler's discretion which fails to meet your intent. This is easy to guess by spotting the violation of the Rule of Three, Four and Five - your class defines the destructor but fails to define the copy and/or move constructor and the assignment operator. As a result your code performs double deletion and therefore cannot be guaranteed any well defined behavior.
Correction 4
Fix the copy semantics of SmartPtr<T>.
I "fixed" your code by assigning move semantics to SmartPtr (this required adding std::move() when insert()-ing it into std::set):
#include<iostream>
#include<set>
template <typename T>
class SmartPtr
{
T *ptr;
public:
explicit SmartPtr(T *p = NULL) { ptr = p; }
~SmartPtr() { delete(ptr); }
SmartPtr(const SmartPtr& other) = delete;
SmartPtr(SmartPtr&& other) : ptr(other.ptr) { other.ptr = NULL; }
SmartPtr& operator=(SmartPtr other)
{
std::swap(ptr, other.ptr);
return *this;
}
T & operator * () const { return *ptr; }
T * operator -> () const { return ptr; }
bool operator<(const SmartPtr& other) const { return ptr < other.ptr; }
};
class simple {
int x;
public:
simple(int y = 0) : x(y) {}
int getX() { return x; }
};
typedef SmartPtr<simple> simplePtr;
int main() {
std::set<simplePtr> st;
simplePtr p1 = simplePtr(new simple(5));
simplePtr p2 = simplePtr(new simple(5));
st.insert(std::move(p1));
st.insert(std::move(p2));
for (const simplePtr& p : st)
{
std::cout << p->getX();
}
return 0;
}
Your iterator needs to be dereferenced, at which point you get a pointer. Which then needs to be dereferenced. So:
std::cout << (*it)->getX();
For starters you have to define operator < for the class SmartPtr before using it in the set.
Secondly you have to declare the member function getX like
int getX() const { return x; }
And you have to write at least like
std::cout << ( *it )->getX();
Related
Yes I know it sounds weird, but I'm looking for a way to overwrite the indirection operator to return another class object. Let me explain better:
In main.cpp I got
MyInt *V = new MyInt[10];
(*V)[3]=10;
but I would like to have it like:
MyInt *V = new MyInt[10];
V[3]=10;
In MyInt.h I've used a wrapper to catch and remove the square brackets of MyInt class and then overload the "=" operator. That's because I need a class that could store the vector and also a counter of its usage inside it. More details here.
MyInt.h
wrapper operator[] ( std::size_t i ) { return wrapper( *this, i ) ; }
The work flow is "MyInt::wrapper::operator=".
Now it works but I would like to get rid of (*V). Would be possible to remove it by overloading the indirection operator to return a wrapper object that could be passed to "wrapper::operator=" then?
I was thinking something like:
MyInt& operator*(){
return wrapper(*this)
}
but it doesn't work, I get "error: invalid initialization of non-const reference of type ‘MyInt&’ from an rvalue of type ‘test::wrapper’". I know that the indirection operator should return the same class, but I really need it that way. Any suggestion? Thanks in advance.
Note: This answer was written when OPs question was:
I would like to have it like:
MyInt V = new MyInt[10];
V[3]=10;
I'll leave this answer up in case anyone is interested in a solution for that.
#include <cstddef>
class MyInt {
public:
MyInt() = default;
MyInt(MyInt* d) : data(d) {} // constructor taking a `MyInt*`
// ... rule of 5 implementation needed here ...
MyInt& operator[](size_t idx) { return data[idx]; }
MyInt& operator=(int) { return *this; }
private:
MyInt* data = nullptr;
};
int main() {
MyInt V = new MyInt[10];
V[3]=10;
}
Note that there's no way for V to know how many elements data is pointing at.
Following the link to your earlier question, and the requirements you've added there, V[3] is undefined behaviour.
You have changed the meaning of new [] to return a pointer to a single object.
You need to completely rethink your design, such that there are 10 MyInt objects for V to point to.
struct MyCounts
{
int num_read = 0;
int num_write = 0;
};
class MyInt
{
int value;
MyCounts * counts;
static void* operator new[](size_t n){
void * ptr = malloc(sizeof(MyCounts) + n * sizeof(MyInt));
MyCounts * counts = new (ptr) MyCounts;
ptr = static_cast<void *>(counts + 1);
for (size_t i = 0; i < n; ++i, ptr += sizeof(MyInt)) {
new (ptr) MyInt{ counts };
}
return static_cast<void *>(counts + 1);
}
static void* operator delete[](void* ptr, size_t n){
for (MyInt * last = reinterpret_cast<MyInt *>(ptr) + n; --last != ptr; ) {
last->~MyInt();
}
ptr -= sizeof(MyCounts);
reinterpret_cast<MyCounts *>(ptr)->~MyCounts();
free(ptr);
}
public:
MyInt& operator=(int i) { value = i; ++counts->num_write; return *this; }
operator int() const { ++counts->num_read; return value; }
};
I would like to have it like:
MyInt* V = new MyInt[10];
V[3]=10;
You need MyInt to implement an operator= taking an int to "write" to it, and a conversion oeprator to "read" from it:
#include <iostream>
struct MyInt
{
int value;
MyInt& operator=(int v) { value = v; return *this; }
operator int() const { return value; };
};
int main()
{
MyInt *V = new MyInt[10];
V[3]=10;
std::cout << V[3] << '\n';
}
Ive been asked to overload this operator: p[d], to do two things,
Return the coefficiant of the polynomial where the degree is d so just p[d].
Change the coefficiant of the polyinomial where the degree is d so p[d]=c.
Im using linked list to make the polynomials.
This is th first one:
double Polynomial::operator[](const int num)
{
Monomial *ptr = NULL;
ptr = this->First;
while (ptr != NULL)
{
if (ptr->get_deg() == num)
{
return ptr->get_C();
}
ptr = ptr->GetNext();
}
return 0;
}
For the second one I was thinking of returning the adress of the monomial with the same degree and change its coefficiant but it doesnt work since both my functions need to get the same paramter( int degree).
This is my second function:
Monomial& Polynomial::operator[](const int num)
{
Monomial *ptr = NULL;
ptr = this->First;
while (ptr != NULL)
{
if (ptr->get_deg() == num)
{
return (*ptr);
}
ptr = ptr->GetNext();
}
return;
}
This is how its tested even though the second part isnt shown here:
cout << "p[0]=" << p[0] << ", p[1]=" << p[1] << ", p[2]=" << p[2] << ", p[4]=" << p[4] << endl;
You don't need two overloads here. Just change the return type of the first to double &.
p[d]=c;
will change the referenced value (the one stored in ptr) to c. This only works, when get_C() also returns a reference of course (Thanks to Holt for mentioning).
Another point, that might be worth mentionig are const instances, because you can't modify the values of const instances. So a one pattern for getters is the following:
class A {
private:
double d;
public:
// Overload for const instances, can't modify 'd' via the rturn value
const double &getD() const { return d; } const;
// for non-const instances
double &get() { return d; }
};
So for const instances (e.g. const A a)
a.getD() = 3;
won't compile, can't modify a const reference. For non-const instances of A this works and would change the actual value of the member d.
double d = a.getD();
will work for both and just copy the value to local variable.
The "canonical" implementation for operator[] can be seen on cppreference.com:
struct T
{
value_t& operator[](std::size_t idx) { return mVector[idx]; }
const value_t& operator[](std::size_t idx) const { return mVector[idx]; }
};
As you can see, the second overload is const-qualified. You cannot call the first overload on non-const object:
const T t;
t[0] = 1; // Error: t is not const, so the second overload is chosen, and you get
// a const value_type& you cannot assign to.
Depending on your implementation, it can make sense to return different type for the read and write overloads, so a correct version would be:
// Create a separate function to avoid duplicated code:
Monomial* Polynomial::get_monomial_or_throw(const int num) {
Monomial *ptr = this->First;
while (ptr != nullptr) {
if (ptr->get_deg() == num) {
return ptr;
}
ptr = ptr->GetNext();
}
throw std::out_of_range("");
}
// const-qualified version for read-only access:
double Polynomial::operator[](const int num) const {
return get_monomial_or_throw(num)->get_C();
}
// Not const-qualified version for write access:
Monomial& Polynomial::operator[](const int num) {
return *get_monomial_or_throw(num);
}
Specifically, I want the following code to fail:
void a(void*){}
int main(){
a(0); // FAIL
a(NULL); // FAIL
a(nullptr); // success
}
And I want the following code to compile:
void a(int){}
void a(void*){}
int main(){
a(0); // calls first a
a(NULL); // calls first a; that's why I have -Werror
a(nullptr); // calls second a
}
The following code does not compile currently, but should according to my rule:
void a(std::size_t){}
void a(void*){}
int main(){
a(0); // two candidates
}
Any idea how to make g++ behave like that?
You can compile with -Wzero-as-null-pointer-constant to get a warning when you use 0 or NULL instead of nullptr. To promote that to an error, I believe using -Werror=zero-as-null-pointer-constant would work.
Unfortunately, this is simply a warning and is not able to change overload resolution rules. I also believe NULL must be defined as 0 rather than nullptr in order for the warning to catch it, but at least as of GCC 4.9, std::is_null_pointer<decltype(NULL)>::value is false and GCC warns when using NULL.
This may not be perfect, but if you trully want to have overloads with int and pointer, you could use some helper class like this:
#include <iostream>
#include <iomanip>
using std::cout;
using std::endl;
template<typename T = void> class ptr {
T* it;
public:
ptr(T* it = nullptr): it(it) {}
ptr(const ptr<T>&) = default;
ptr& operator = (const ptr<T>&) = default;
operator T* () { return it; }
T& operator * () { return *it; }
T* operator -> () { return it; }
ptr& operator += (int x) { it += x; return *this; }
ptr& operator -= (int x) { it -= x; return *this; }
ptr& operator ++ () { ++it; return *this; }
// etc...
public:
template<typename P>
ptr(P* it): it(it) {}
template<typename P>
ptr(ptr<P> it): it((T*)it) {}
};
template<> class ptr<void> {
void* it;
public:
ptr(void* it = nullptr): it(it) {}
ptr(const ptr<void>&) = default;
ptr& operator = (const ptr<void>&) = default;
operator void* () { return it; }
public:
template<typename P>
ptr(P* it): it(it) {}
template<typename P>
ptr(ptr<P> it): it((void*)it) {}
};
void a(std::size_t x) {
cout << "first: " << x << endl; }
void a(ptr<const int> p) {
cout << "second: " << (p ? *p : -1) << endl; }
void a(ptr<int> p, ptr<> q) {
cout << "third: " << (p ? *p : -1) << ", "
<< (q ? "some" : "null") << endl;
a(p); }
int main(){
a(0); // first: 0
a(NULL); // first: 0 but warning [-Wconversion-null]
a(new int(3), nullptr); // third: 3, null + second: 3
}
It is not finished (maybe remove that explicit, add more operators, special conversion from nullptr_t, etc), just and idea.
EDIT: Few changes in code, template constructors and conversion to ptr<const int> test.
Given that NULL is either identical to 0 or nullptr, I don't think you can force a C++ compiler to behave the way you describe it. I could imagine using clang's AST interface to detect the cases exactly the way you describe. I'd expect that typical C++ code will contain a number of intentional uses of 0 and/or NULL to mean pointers and/or integers as appropriate.
Here is a relatively simple solution to the first problem (it requires C++11):
struct must_be_void_ptr{
must_be_void_ptr(void* p) : p(p) {}
must_be_void_ptr(int) = delete; // Disallow implicit conversion from 0
void* p;
operator void*() { return p; }
};
void a(must_be_void_ptr p){
void* vp = p;
}
int main(){
a(nullptr);
a(0);
}
Use:
gsl::not_null
From Guideline Support Library. I highly recommend GSL. It's created and backed by many C++ experts, Bjarne Stroustrup himself and Herb Sutter among them. And the C++ Core Guidelines are actively being integrated into the compiler warnings and static analyzers.
I've tried to figure out what is the purpose of & on the return type. I mean,consider the code below, what happens if i delete & from the operator overloading function.
class Container
{
public:
int numElems;
int *data;
Container(int n):numElems(n){data=new int [numElems];}
Container & operator=(const Container &rhs)
{
if(this!=&rhs)
{
if(data!=NULL)
delete [] data;
numElems=rhs.numElems;
data=new int [numElems];
for (int i=0;i<numElems;i++)
{
data[i]=rhs.data[i];
}
return *this;
}
}
};
I deleted it and compile it ,it compiled without any errors.Actualy it gives the same result in both cases for an example main:
int main()
{
Container a(3);
Container b(5);
Container c(1);
cout<<a.numElems<<endl;
cout<<b.numElems<<endl;
cout<<c.numElems<<endl;
a=b=c;
cout<<a.numElems<<endl;
cout<<b.numElems<<endl;
cout<<c.numElems<<endl;
return 0;
}
So, is there anyone who can help me about the purpose of & on the left side ? Thanks in advance.
class foo {
public:
int val;
foo() { }
foo(int val) : val(val) { }
foo& operator=(const foo &rhs) {
val = rhs.val;
return *this;
}
foo& operator++() {
val++;
return *this;
}
};
void main() {
foo f1(10), f2;
(f2 = f1)++;
std::cout << f1.val << " " << f2.val << std::endl;
}
Output:
10 11
Output when removing reference:
10 10
Returning a reference is much faster than returning a value for a large object. This is because under the hood a reference is just a memory address whereas if you return it by value it requires a deep copy
If you don't return a reference, you implicitly make an extra unnecessary copy.
I have the following code:
#include <iostream>
struct Base {
int i_;
};
class El : protected Base {
public:
int get_i() const { return i_; }
void set_i(int i) { i_ = i; }
};
class It : protected Base {
public:
using pointer = const El*;
using reference = const El&;
reference operator*() const
{
return reinterpret_cast<reference>(*this);
}
pointer operator->() const
{
return reinterpret_cast<pointer>(this);
}
};
int main()
{
It it;
It* itp = ⁢
std::cout << *****(itp)->get_i() << "\n"; //ERROR
}
Both GCC and Clang++ somehow fail to invoke either of operator* or operator->, so I get an error It doesn't have member function 'get_i' in the last line regardless how many indirections I try. Does the standard warrant such unintuitive behavior?
Operator precedence: -> binds more tightly, so is applied to the pointer itp.
When you overload operator->, that doesn't affect the meaning of operator-> applied to a pointer-to-your-class. You want (*itp)->get_i();, I think.