This code complies:
template <class T>
class A {};
void main () {
A<int> a;
vector<A<int>> vec;
vec.push_back(a);
}
but this doesn't:
void main () {
SharedPointer<int> sp;
vector<SharedPointer<int>> vec;
vec.push_back(sp);
}
I get this error:
error C2558: class 'SharedPointer' : no copy constructor available
or copy constructor is declared 'explicit'
SharedPointer header: (all methodes are implemented in the header)
#include <iostream>
#include "Myexception.h"
using namespace std;
#pragma once
template<class T>
class SharedPointer {
T* ob;
int* refcount;
bool shareable;
int refdown();
int refup();
void markUnshareable();
public:
virtual ~SharedPointer();
SharedPointer():shareable(true);
SharedPointer(T pointee):shareable(true);
SharedPointer(SharedPointer<T>& sp);
SharedPointer operator=(const SharedPointer<T>& sp);
bool operator==(const SharedPointer<T>& sp);
const T& operator[](const int idx) const;
T& operator[](const int idx);
T* operator->() const;
T& operator*() const;
void setOb(T pointee);
const T& getOb() const;
int getRefcount();
bool isShareable();
bool isShared();
};
The problem is that the copy constructor:
SharedPointer(SharedPointer<T>& sp);
can't only be used to copy a const pointer. Add the missing const and all should be fine:
SharedPointer(const SharedPointer& sp); // <T> is harmless, but unnecessary
(You'll also have to fix the syntax errors in the constructor definitions, and you should change the return type of main to int. Removing using namespace std; would also be a good idea.)
Your copy constructor declared
SharedPointer(SharedPointer<T>& sp);
should look like :
SharedPointer(const SharedPointer<T>& sp);
so the compiler will find the missing copy constructor
Related
I have a C++ code that currently looks like this: there is a class hierarchy to do perform some comparison and a list class that uses it. Which comparison operation to use is determined at runtime based on some schema object. Here is the structure:
class A{
bool doComparison(const string& s1, const string& s2) const=0;
}
class B: public A{
bool doComparison(const string& s1, const string& s2) const {
...
}
}
class C: public A{
bool doComparison(const string& s1, const string& s2) const {
...
}
}
template <class, S>
public FancyList{
shared_ptr<A> z_;
vector<S> v;
FancyList(shared_ptr<A> z) : z_(z);
void DoSmth(){
....
z_->doComparison(arg1, arg2);
}
}
typedef FancyList<string> FancyStringList;
// Determine which comparison to use at runtime
shared_ptr<A> c = nullptr;
switch(type):
case int:
c = make_shared<B>();
break;
case double:
c = make_shared<B>();
break;
FancyStringList l(c);
l.push_back("stuff");
C# used to be my main language so this code seemed ok to me. But I was told that the problem with this approach is that it uses virtual functions so there is a slight overhead in a method call. What is the proper C++-way of reorganizing this code so there is no need to have this class hierarchy and no need to use virtual functions?
Contrary to what you want, the overhead of virtual function is unavoidable because the decision of which actual function is called is made in runtime.
If the decision is always made in runtime, the compiler cannot hard-code the function call into the generated machine code. It has to be a indirect function call: to use a pointer to point to a function, and to dereference the pointer before the function call. Virtual function is just one way to do indirect function call.
Template is a way tell the compiler to generate code during compile-time. All template can do is to not introduce overhead when the decision is made during compile-time. It can't help you remove works that must be done in runtime.
If you are still interested in using template, you may consider having the comparator as a template parameter.
template <class T, class Comparator>
class MyList
{
std::vector<T> vec;
Comparator comp;
public:
void do_thing(const T& a, const T& b)
{
vec.push_back(a);
vec.push_back(b);
bool x = comp(vec[0], vec[1]); // for example
std::cout << x;
}
};
In the comparator class, overload the function call operator.
class Compare1
{
public:
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return lhs < rhs;
}
};
class Compare2
{
public:
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return lhs.size() < rhs.size();
}
};
int main()
{
MyList<std::string, Compare1> myli1;
myli1.do_thing("a", "b");
MyList<std::string, Compare2> myli2;
myli2.do_thing("c", "d");
}
You can even hide indirect function call behind comparator class. But it does not remove the overhead.
class A
{
public:
virtual bool doComparison(const std::string& s1, const std::string& s2) const=0;
virtual ~A() = default;
};
class PolymorphicComparator
{
private:
std::shared_ptr<A> comp;
public:
PolymorphicComp(std::shared_ptr<A> c) : comp(c) {}
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return comp->doComparison(lhs, rhs);
}
};
Is there a short-cut to using std::unordered_set with classes that implement operator== and hash? Specifically, is there a way to (1) avoid creating a stand-alone operator==(const Object& a, const Object& b) function, and (2) avoid defining an entire class just to hold size_t operator()(const Object& o) const {return o.hash();}
Of course, neither of these are problems, I'm just curious.
operator== being defined as a member function is already catered for.
If the class being used as a key has a member function hash() const then we can do something simple like this:
-
#include <unordered_map>
#include <string>
struct myclass {
std::size_t hash() const { return 0; }
bool operator==(const myclass& r) const { return true; }
};
struct self_hash
{
template<class T>
auto operator()(const T& r) const { return r.hash(); }
};
int main()
{
using mymap = std::unordered_map<myclass, std::string, self_hash>;
auto m = mymap();
}
I am implementing an iterator for a Queue data type, but the iterator is being initialized as a const inside of the class implementation for some reason. I cannot figure out why the constructor is causing the iterator to return itself as a const.
Any feedback as to what the intricasies of the C++ language that may be causing my problem could be, would be very helpful.
The Error I am receiving from Eclipse which seems to be coming from my begin() method is:
../src/linked_queue.hpp:315:35: error: invalid conversion from
'const ics::LinkedQueue<int>*' to 'ics::LinkedQueue<int>*' [-fpermissive]
Interface:
#ifndef LINKED_QUEUE_HPP_
#define LINKED_QUEUE_HPP_
#include <string>
#include <iostream>
#include <sstream>
#include <initializer_list>
#include "ics_exceptions.hpp"
namespace ics {
template<class T> class LinkedQueue {
public:
//Destructor/Constructors
~LinkedQueue();
LinkedQueue ();
LinkedQueue (const LinkedQueue<T>& to_copy);
explicit LinkedQueue (const std::initializer_list<T>& il);
template <class Iterable>
explicit LinkedQueue (const Iterable& i);
//Queries
bool empty () const;
int size () const;
T& peek () const;
std::string str () const; //supplies useful debugging information; contrast to operator <<
//Commands
int enqueue (const T& element);
T dequeue ();
void clear ();
template <class Iterable>
int enqueue_all (const Iterable& i);
//Operators
LinkedQueue<T>& operator = (const LinkedQueue<T>& rhs);
bool operator == (const LinkedQueue<T>& rhs) const;
bool operator != (const LinkedQueue<T>& rhs) const;
template<class T2>
friend std::ostream& operator << (std::ostream& outs, const LinkedQueue<T2>& q);
private:
class LN;
public:
class Iterator {
public:
~Iterator();
T erase();
std::string str () const;
LinkedQueue<T>::Iterator& operator ++ ();
LinkedQueue<T>::Iterator operator ++ (int);
bool operator == (const LinkedQueue<T>::Iterator& rhs) const;
bool operator != (const LinkedQueue<T>::Iterator& rhs) const;
T& operator * () const;
T* operator -> () const;
friend std::ostream& operator << (std::ostream& outs, const LinkedQueue<T>::Iterator& i) {
outs << i.str();
return outs;
}
friend Iterator LinkedQueue<T>::begin () const;
friend Iterator LinkedQueue<T>::end () const;
private:
LN* prev = nullptr;
LN* current;
LinkedQueue<T>* ref_queue;
int expected_mod_count;
bool can_erase = true;
Iterator(LinkedQueue<T>* iterate_over, LN* initial);
};
Iterator begin () const;
Iterator end () const;
private:
class LN {
public:
LN () {}
LN (const LN& ln) : value(ln.value), next(ln.next){}
LN (T v, LN* n = nullptr) : value(v), next(n){}
T value;
LN* next = nullptr;
};
LN* front = nullptr;
LN* rear = nullptr;
int used = 0; //Cache for number of values in linked list
int mod_count = 0; //For sensing any concurrent modifications
//Helper methods
void delete_list(LN*& front);
};
Implementation (I've included only a section of my Iterator code):
template<class T>
auto LinkedQueue<T>::begin () const -> LinkedQueue<T>::Iterator {
return Iterator(this, this->front);
}
template<class T>
auto LinkedQueue<T>::end () const -> LinkedQueue<T>::Iterator {
// return Iterator(this, this->rear);
}
template<class T>
LinkedQueue<T>::Iterator::Iterator(LinkedQueue<T>* iterate_over, LN* initial) {
ref_queue = iterate_over;
expected_mod_count = iterate_over->mod_count;
current = initial;
}
The error is because Iterator begin () const; is marked as const, hence the this used in the function is const as well. So in turn, the compiler gives the error that it cannot convert from a const to non-const.
Given that the function signatures are fixed in this case, to resolve the error, added const will help solve the issue.
You could add const to the constructor signature
Iterator(LinkedQueue<T> const* iterate_over, LN* initial);
And make the member const as well
LinkedQueue<T> const* ref_queue;
Adding the const where required to ensure that members and functions remain const as required is known as being const correct.
Here's the simple example class with hash function I wrote. Function maybe isn't most efficient one, but quality of hash function isn't relevant to me for now.
#include<iostream>
#include<unordered_set>
using namespace std;
class Class{
private:
int num;
public:
Class(int n){num=n;}
Class(){num=0;}
int getNum(){return num;}
friend bool operator==(const Class &k1, const Class &k2);
};
bool operator==(const Class &k1, const Class &k2){
return(k1.num == k2.num);
}
namespace std {
template <>
struct hash<Class>{
size_t operator()(const Class & c) const
{
return(31+c.getNum()*7);
}
};
}
void main(){
unordered_set<Class> set;
set.insert(Class(5));
set.insert(Class(55));
set.insert(Class(4));
set.insert(Class(123));
set.insert(Class(11));
for(unordered_set<Class>::iterator it = set.begin(); it!=set.end(); it++)
cout<<it->getNum()<< endl;
}
This worked fine when all fields of Class were public, but errors appear in hash function at return(31+c.getNum()*7); on c, because I can't call getNum() function. I don't know if there is any problem if in line size_t operator()(const Class & c) const I remove const, so object c is not const?
Also, in the last line, cout<<it->getNum()<< endl, there is error when accessing getNum() function. I don't know how to iterate over unordered_set set and to print num.
Your operator takes a const class but calls a non-const member function. To fix your issue declare getNum as const since it does not modify the class.
class Class{
private:
int num;
public:
Class(int n) : num(n) {}
Class() : num(0) {}
int getNum() const { return num;}
friend bool operator==(const Class &k1, const Class &k2);
};
In the above example also notice that I used member initializer lists to instantiate member variables. Also change the return type from void to int on main and I recommend either returning 0 or EXIT_SUCCESS from <cstdlib> at the end of main.
why i need to use the const function in the less traits?
for example, why i must use const in Age or ID member function.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
#include <string>
#include <set>
using namespace std;
class Person
{
public:
Person(int id, string name, int age):m_iID(id), m_strName(name), m_iAge(age){};
int Age() const {return m_iAge;}
int ID() const {return m_iID;}
void Display();
friend ostream& operator<<(ostream& out, Person& person);
private:
int m_iID;
string m_strName;
int m_iAge;
};
void Person::Display()
{
cout<<m_iID<<" "<<m_strName<<" "<<m_iAge<<endl;
}
ostream& operator<< (ostream& out, Person& person)
{
out<<person.m_iID<<" "<<person.m_strName<<" "<<person.m_iAge<<endl;
return out;
}
int SumPersonAge(int iSumAge, Person& person)
{
return iSumAge + person.Age();
}
template <typename Type>
void Display(Type t1)
{
cout<<t1<<endl;
}
class LessPerson
{
public:
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
};
int main()
{
set<Person, LessPerson> s1;
Person p1(1234, "Roger", 23);
Person p2(1235, "Razor", 24);
s1.insert(p1);
s1.insert(p2);
for_each(s1.begin(), s1.end(), Display<Person>);
}
if i remove the const the keyword in Age or ID function, the compiler will report me Error cannot convert 'this' pointer from 'const Person' to 'Person &'.
The answer is that the set will pass two const reference to Person objects to your comparator, and you cannot call a non-const function on a const variable.
You might be surprised as there seems not to be any const in the declaration of the functor:
struct LessPerson
{
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
};
But there is, it is just not explicit in the code. Inside the set implementation there are two const Person& references (call them r1, r2) and a LessPerson comparator (call it compare) and the code does something in the lines of if ( comparator(r1,r2) ). The compiler finds the templated operator() and tries to infer the types ending up with the type substitution: Type == const Person.
Why does the set use const references rather than plain modifiable references? Well, that is a different issue. The set is implemented as a sorted balanced tree, with each node containing the key. Now because a change in the key would break the order invariant, the keys are themselves const objects, ensuring that you cannot break the invariants.
That const keyword means that the function does not modify its object, this. Only const functions may be called from const objects. So, the compiler is telling you that you are trying to call a non-const member function from a const object.
You appear to be avoiding the const keyword, but it creeps in when the library calls your template function:
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
Type is passed as const Person.
const is not easy to get rid of without cheating, and it will always creep in. It's better to go with the flow and add const everywhere you take a reference that doesn't change an object (which is most of them).
Because the type passed to LessPerson is const Person.
So basically, LessPerson is roughly
class LessPerson
{
public:
bool operator()(const Person& t1, const Person& t2)
{
return t1.ID() < t2.ID();
}
};
You can't call non-const methods on const objects. It's a rule of C++.