I haven't used void* and const_correctness before so I am not understanding what I am doing wrong in the below code. All I want is to cast a void* returned by a member function of a const object to int*. Please suggest better approaches. Thank you.
I get the following error
passing 'const MyClass' as 'this' argument of 'void* MyClass::getArr()' discards qualifiers
So here's the actual program that I had problem with
class MyClassImpl{
CvMat* arr;
public:
MyClassImpl(){arr = new CvMat[10];}
CvMat *getArr(){return arr;}
};
class MyClass{
MyClassImpl *d;
public:
const void *getArr()const{ return (void*)d->getArr(); }
};
void print(const MyClass& obj){
const int* ptr = static_cast<const int *>(obj.getArr());
}
int main(){
MyClass obj1;
print(obj1);
}
Only the methods such as 'print()' in this case know the datatype returned by 'getData'. I can't use templates because the user doesn't know how MyClass is implemented. Thank you. Feel free to suggest alternatives.
I think the problem is not in the cast from your array to a void * but in trying to call obj.getArr() when obj is marked const and MyClass::getArr() is not a const member function. If you change your definition of that member function to
const void *getArr() const { return static_cast<const void*>(arr); }
Then this error should resolve itself. You might want to do a const-overload as well:
const void *getArr() const { return static_cast<const void*>(arr); }
void *getArr() { return static_cast< void*>(arr); }
Related
Say I have a simple class like this
class Foo
{
public:
void foo()const
{
str[5] = 'x';
obj->changeTheWorld();
x = 4;
y.get() = 5;
obj2->changeTheWorld();
}
private:
char *str; //some referenced data, not owned by Foo
ComplexObj *obj; //some referenced data, not owned by Foo
int &x; //references as well
//wrapped reference, but has a "T& get()const"
std::reference_wrapper<int> y;
//an occasionally useful pointer wrapper for complex memory cases
//but has a "T* get()const"
std::shared_ptr<ComplexObj> obj2;
};
This is valid because in the const method, its just the pointer itself that becomes const, not the data it points to. However in many cases that is not what I desired and I want a compile error if a const method tries to change these members contents (either directly or by calling a non-const method on that member).
Is there a standard solution to this?
I think some kind of wrapper class should be able to achieve this, and should also be something the compiler optimises out, although haven't sat down to try and design such a thing to cover all cases giving say a strong_const<char*> str and strong_const<int&> (also not sure on a good name...).
Well, neither std::reference_wrapper nor std::shared_ptr do not provide const propagation, so they are not more "const-strict" than regular pointer.
I'd recommend to make your own const propagation class (I am not sure - maybe something similar is already provided by boost - please let me know in comments)
My proposition is this class:
#include <memory> // for pointer_traits
template <typename Pointer>
class ConstPropagatePointer
{
public:
using element_type = typename std::pointer_traits<Pointer>::element_type;
using pointer = typename std::pointer_traits<Pointer>::pointer;
using const_pointer = element_type const * const;
using reference = element_type&;
using const_reference = element_type const&;
ConstPropagatePointer(Pointer ptr) : ptr(ptr) {}
pointer operator -> ()
{
return &(*ptr);
}
const_pointer operator -> () const
{
return &(*ptr);
}
reference operator * ()
{
return *ptr;
}
const_reference operator * () const
{
return *ptr;
}
private:
Pointer ptr;
};
So that will work for you:
class Foo
{
public:
private:
ConstPropagatedPointer<char*> str;
ConstPropagatedPointer<ComplexObj*> obj;
ConstPropagatedPointer<std::shared_ptr<ComplexObj>> obj2;
};
I am currently trying to use the "this" pointer to pass a pointer to a function:
void GameObject::process_events()
{
std::vector<ObjectEvent*>::iterator it;
for (it = events.begin(); it != events.end(); it++)
(*it)->process(this);
}
Class ObjectEvent
{
private:
bool* trigger;
void (*response)(GameObject*);
public:
process(GameObject* obj)
{
if (*trigger)
response(obj);
}
};
But I get an error:
No matching function call to 'ObjectEvent::process(GameObject* const)'
What could be the problem?
Judging by your error message, process_events() appears to actually be a const function.
void GameObject::process_events() const
{
process(this);
}
If so, then this is a const pointer and process() must take a const GameObject *. Otherwise process() could modify the point that gets passed to it, which violates process_events's promise not to modify this.
void process(const GameObject* obj);
Alternatively, remove the const modifier from process_events().
If the member function you're returning this from or using this in is const, then it will be a const pointer. If the member function is not declared const, the pointer won't be either.
void GameObject::process_events()
{
// ...
process(this); // 'this' is NOT a const pointer
}
void GameObject::process_events() const
{
// ...
process(this); // 'this' IS a const pointer
}
I want to a member variable, which is a double pointer. The object, the double pointer points to shall not be modified from outside the class.
My following try yields an
"invalid conversion from ‘std::string**’ to ‘const std::string**’"
class C{
public:
const std::string **getPrivate(){
return myPrivate;
}
private:
std::string **myPrivate;
};
Why is the same construct valid if i use just a simple pointer std::string *myPrivate
What can i do to return a read-only double pointer?
Is it good style to do an explicit cast return (const std::string**) myPrivate?
Try this:
const std::string * const *getPrivate(){
return myPrivate;
}
The trouble with const std::string ** is that it allows the caller to modify one of the pointers, which isn't declared as const. This makes both the pointer and the string class itself const.
If you want to be really picky :
class C {
public:
std::string const* const* const getPrivate(){
return myPrivate;
}
private:
std::string **myPrivate;
};
There are very rare cases in c++ when a raw pointer (even less for a double pointer) is really needed, and your case doesn't seams to be one of them. A proper way would be to return a value or a reference, like this :
class C{
public:
const std::string& getPrivate() const
{
return myPrivate;
}
private:
std::string myPrivate;
};
I'm stuck on a compiler error and I can't seem to find a solution online (mainly because google can't handle the syntax). This is the one and only error I'm getting (MVS 2005).
error C2664: 'LinkedList<T>::CreateLinkedList' : cannot convert parameter 2
from 'const MemberInfo *' to 'MemberInfo *const *' memberdata.cpp 59
The error points to this piece of code.
ILinkedList*
MemberData::CreateLinkedList()
{
const MemberInfo* mi = this->get(FIRST);
LinkedList<MemberInfo*>::CreateLinkedList(
MemberInfo::CompareByTime,
mi);
return NULL;
}
The relevant pieces of code in this are:
MemberInfo class
// MemberInfo declaration
class
MemberInfo
{
public:
static int
CompareByTime(
const void* mi1,
const void* mi2);
};
// MemberInfo implementation
int
MemberInfo::CompareByTime(
const void* mi1,
const void* mi2)
{
if ( mi1 == NULL || mi2 == NULL )
return 0;
if ( ((MemberInfo*)mi1)->m_Time > ((MemberInfo*)mi2)->m_Time )
return 1;
if ( ((MemberInfo*)mi2)->m_Time > ((MemberInfo*)mi1)->m_Time )
return -1;
return 0;
}
LinkedList class
typedef int (*ComparatorFcn)(const void*, const void*);
template <class T>
class LinkedList
: public ILinkedList
{
private:
protected:
const T*
m_ptValue;
ComparatorFcn
m_pCompFcn;
LinkedList(
const T* ptVal,
ComparatorFcn func);
public:
static ILinkedList*
CreateLinkedList(
ComparatorFcn func,
const T* ptVal)
{
LinkedList<T>* t = new LinkedList<T>(ptVal, func);
return t;
}
virtual
~LinkedList();
LinkedList<T>*
AddLink(
T* pLink);
virtual bool
Remove();
virtual bool
RemoveLink(
ILinkedList* pLink);
};
I'm quite stuck. I don't understand why the compiler thinks that my argument for the function CreateLinkedList is MemberInfo *const *rather than how I declared it as const MemberInfo* (or const T* actually).
Any help ideas?
Thanks!
Your LinkedList<MemberInfo*> should be LinkedList<MemberInfo>.
Notice that the error message mentions MemberInfo *const * - a pointer to a pointer.
As the type you use to instantiate the template is a MemberInfo *, T will be MemberInfo * and the CreateLinkedList functions expects a T const * aka a MemberInfo * const *.
The type you pass is a MemberInfo const * aka const MemberInfo *.
So, you're asking the compiler to convert from const MemberInfo * to MemberInfo * const *
I see a couple problems:
First, your MemberInfo::CompareByTime() function is written wrong. The way you have written it throws away any type checking the compiler can do. Better would be:
int MemberInfo::CompareByTime(const MemberInfo& mi1, const MemberInfo& mi2)
{
if(mi1.m_Time > mi2.m_Time)
return 1;
if(mi1.m_Time < mi2.m_Time)
return -1;
return 0;
}
Second, pass the comparison function into your linked list as a template parameter:
template <class T, int (*CompFcn)(const T&, const T&)>
class LinkedList: public ILinkedList
Third, there's no reason to hide the constructor and wrap it in a static function that returns the superclass' pointer. C++ will automatically convert an object's pointer to a pointer to its superclass when needed. Also, you should be passing the contained values around by reference (instead of pointer) and store them by value when possible; if you want your container to store pointers, then just set T to a pointer type. So your construction simplifies to:
protected:
T m_ptValue;
public:
LinkedList(const T& ptVal);
Finally, your code for MemberData::CreateLinkedList is broken. It always returns NULL. That is, from the outside it looks like it never creates a linked list. Also, the this-> does nothing. What you should have is:
LinkedList<MemberInfo*, MemberInfo::CompareByTime>* MemberData::CreateLinkedList()
{
return new LinkedList<MemberInfo*, MemberInfo::CompareByTime>(get(FIRST));
}
Though it's probably good practice to define typedef LinkedList<MemberInfo*, MemberInfo::CompareByTime> LinkedListType; in MemberData, which lets us write:
MemberData::LinkedListType* MemberData::CreateLinkedList()
{
return new LinkedListType(get(FIRST));
}
Note that the return value will be typecast to ILinkedList* automatically where needed.
First of all, there is no difference between const T and T const. It is allowed to add the const keyword after the type. In many situations that is the only way to exactly specify what part of the type const is.
You are using const T* (or T const *). where T is MemberInfo*:
LinkedList<MemberInfo*>::CreateLinkedList(
So the full type is MemberInfo * const *. Note that this is not the same as const MemberInfo * * (or MemberInfo const * *).
Please take a look at this code and run it:
I'm getting very strange error:
Error 1 error C2663: 'Allocator::allocate_help' : 2 overloads have no legal conversion for 'this' pointer
template<class FailureSignal>
class Allocator
{
private:
template<class Exception,class Argument>
void allocate_help(const Argument& arg,Int2Type<true>)
{
}
template<class Exception,class Argument>
std::nullptr_t allocate_help(const Argument& arg,Int2Type<false>)
{
return nullptr;
}
public:
template<class T>
void Allocate(signed long int nObjects,T** ptr = 0)const
{
allocate_help<std::bad_alloc>(1,Int2Type<true>());
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Allocator<int> all;
all.Allocate<int>(1);
return 0;
}
I absolutely do not understand this err msg. Hope someone can help me with this. Thank you.
I noticed Allocate is declared const but allocate_help is not - could that be related to the issue?
I had the same error which was also caused by const but in a bit different way.
I have two virtual functions (overloads), one was const and the other was not. This was causing the problem. Turns out if you want to overload a function, they both need to match if they are const or not.
virtual void value() const = 0;
virtual void value(MyStruct & struct) = 0;
The above code will cause this error. The fix is to change declaration of 2nd to:
virtual void value(MyStruct & struct) const = 0;
I had this problem, when i tried to change member data in a const declared method.
As we all know, const methods are supposed not to change member data.
The compiler gcc/clang doesn't return good error message.
It successfully compiled after removing const specifier from
void I_am_a_const_method_but_trying_to_modify_member() const{
amap.emplace(std::make_tuple(1, 1, "a"), 1);
}
compiler explorer link