This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
c++ passing a const object reference to a function
void SpectrumAnalyserThread::calculateFFT(AnalogData &frame, const QByteArray &playbackBuffer)
{
fft->window(frame.data(),frame.size());
fft->fix_fftr(frame.data(), qFloor(log(frame.size()) / log(2)), 0);
for(int i = 0; i < m_numSamples; ++i)
{
m_output.push_back(frame[i]);
}
fft->fix_fftr(m_output.data(), qFloor(log(m_output.size()) / log(2)), 0);
const QByteArray ba((const char*)m_output.data(), sizeof(ushort));
const_cast<QByteArray &>(playbackBuffer);
playbackBuffer.append(ba);
m_output.clear();
calculateMagnitude(frame);
}
I get the following error:
error: passing 'const QByteArray' as 'this' argument of 'QByteArray& QByteArray::append(const QByteArray&)' discards qualifiers [-fpermissive]
If I make the function const then it throws errors at
m_output.clear(), m_output.push_back(), which is obvious but I need to clear the buffer so that when the function is called again previous data does not get appended.
If you want to modify playbackBuffer then you should take the parameter as a non-const parameter:
QByteArray &playbackBuffer
This is completely independent of whether the member function of SpectrumAnalyserThread is declared const (which it shouldn't be if it modifies this' internal state).
Note that this line has no effect. To use the result of a cast you must do something with it. A statement that is a cast alone just performs the conversion and then throws the result of that conversion away.
const_cast<QByteArray &>(playbackBuffer);
You could do something like below but it risks undefined behaviour and is an abuse of the contract you have with callers of your function where you say, by taking a const reference, that you're not going to modify playbackBuffer.
const_cast<QByteArray &>(playbackBuffer).append(ba);
The problem is at
playbackBuffer.append(ba);
You want to mutate playbackBuffer, so don't pass it as a const reference.
const_cast returned an object of type QByteArray& (it wiped off const from the original type) but you didn't do anything with that object - the type of the playbackBuffer didn't change - it remained const QByteArray&.
You can do two things:
1) call class method on a temporary unnamed variable of type QByteArray& returned by the cast operator:
const_cast<QByteArray &>(playbackBuffer).append(ba);
2) assign return value of the cast operator to the local variable of type QByteArray& (if you want to use it again to call non-const member functions):
QByteArray& playbackBufferNonConstRef = const_cast<QByteArray&>(playbackBuffer);
playbackBufferNonConstRef.append(ba);
Regardless of this, you should first think of why passing an object as a const reference and then trying to trick it and change it after casting const away. If you declare function's argument as a const reference, your clients will believe that object passed to it won't be changed. But with this design they'll be getting unexpected results...
Related
I'm having the below method with multiple const keywords. why are they used?
const int* MyClass::getvalue(const int input) const
if returning a pointer from a method, what are the ways to restrict the user from changing the pointer value and pointer itself?
First of all, having the return type for a value (as opposed to a reference or a pointer) being const is rather useless. The caller of the function can still copy the value to a non-constant variable anyway. For a reference or a pointer, it means that the referenced/pointed to object can not be modified. It can still be copied to a non-constant object though.
The argument being const means that the function can not change the argument. It is partly informational, partly helps the compiler choose optimizations, and for references or pointers means that whatever is referenced/pointed to can't be modified. For references there's also the semantic that you can pass temporary objects to the function.
The last const is for the function itself, and makes it so that the function can only be called on const objects. If you have a non-const MyClass object, this function can't be called on it. This const is part of the function signature, together with the function name and its argument types. That means you can have two overloaded functions with the same name and arguments, one being const qualified and one not.
I'm having the below method with multiple const keywords. why are they used?
const int MyClass::getvalue(const int input) const
^
This makes the return value const. There is no reason to use a return by const value. Some compilers will warn if you use const here. Note that conversely, a reference or a pointer to const object would be reasonable.
const int MyClass::getvalue(const int input) const
^
This makes the argument const. Whether a value argument is const or not makes little difference. A minor advantage of const is that you can know from the declaration that the local object won't change throughout the function, which can be helpful if the function is complex.
const int MyClass::getvalue(const int input) const
^
This makes a member function const. This allows the member function to be called on const instances of the class, but also prevents the function from modifying non-mutable members of the object.
if returning a pointer from a method, what are the ways to restrict the user from changing the pointer value and pointer itself?
There is no way of restricting the user from changing the value of a pointer object that you've returned to them, and there is never a need to do so.
You can restrict the user from modifying the pointed object by returning a pointer to const.
The last const specifies that getvalue() won't change the instance of MyClass it is called upon.
const int input declares a parameter of type int to the function getvalue() specified as const. Its value cannot be changed inside the function.
In the return type const is quite meaningless since the returned value can be assigned to a non-const-qualified int without problem.
what are the ways to restrict the user from changing the pointer value and pointer itself?
Read declarations backwards:
int const * const foo; // foo is a constant pointer to a constant int
int * const bar; // bar is a constant pointer to a int
int const * qux; // qux is a pointer to a constant int
I would like to return a pointer to an array owned by a class. However, I do not want to allow users to modify that data or pointer. According to how I understand things you need return a constant pointer to constant data using the following syntax.
const Type *const Class::Method() {
return this->data_;
}
However gcc gives the following warning when compiling.
warning: type qualifiers ignored on function return type
Why is this warning provided by gcc? What does it mean? If this is not the right syntax for what I want, what is?
The warning you get is because the final const is overlooked. Take it off and you're set.
You don't need to return a const pointer to const data, just a pointer to const data (which is const Type*). Just as it doesn't make sense to return a const int, it doesn't make sense to return a T* const, because as soon as the value is assigned to a new variable, that const is discarded.
The top level const is ignored for built-in types. As there is a rule in C++[3.14p4]: class and array prvalues can have cv-qualified types; other prvalues always have cv-unqualified types.. In your case const Type* const, the top level const making the pointer const is ignored.
You could add const to the end: const Type * Class::Method() const {...}. This would prevent the pointer from being modified inside the member function. However, since the member function returns prvalue which is non-modifiable, it is not necessary to do this to prevent modification of the pointer member outside of the class (and this is also the reason why this rule exists in C++). It may be useful when you want to call the function with a constant reference to a Class object, etc., but for what you are doing, this doesn't seem necessary.
First const is right, the second const does not make any sense. Just look at this example:
const int foo();
int a = foo();
The fact if foo returns const int or just int does not change anything in this case. Same for Type *.
Here's a code snippet that hopefully conveys what I'm trying to do:
void updatePointer(const int*& i)
{
i++;
}
int main() {
int array[5];
int* arrayPtr = array;
updatePointer(arrayPtr );
return 0;
}
This gives compiler error:
prog.cpp: In function ‘int main()’:
prog.cpp:16: error: invalid initialization of reference of type ‘const int*&’ from
expression of type ‘int*’
prog.cpp:5: error: in passing argument 1 of ‘void updatePointer(const int*&)’
Supposing that you could do it, you could write the following:
const int c = 0;
void updatePointer(const int* &i) {
i = &c;
}
int main() {
int *ptr;
updatePointer(ptr);
*ptr = 1; // attempt to modify the const object c, undefined behavior
}
The purpose of const is to ensure that user code cannot attempt to modify a const object unless it contains a const-cast (or equivalent). So the compiler has to refuse this code. Forbidding a const int*& from binding to an int* is the only place in the code above that's reasonable for the compiler to refuse: every other line is fine.
It's the same reason you can't implicitly convert int** to const int **.
Aside from the motivation in terms of const-safety, you can think if it in terms of int* being a different type from const int*, that just so happens to be convertible to it. Likewise, you can convert int to double, but a double& can't bind to an int lvalue. That's not the full reason, because actually int* and const int* have the same size and representation, whereas int and double don't. So there could be a special-case to allow it if not for the fact that it would break the const system.
The reason that C++ has both const and non-const overloads for strchr is related to this issue: your function updatePointer modifies its input rather than returning the updated value, but the principle is similar. The C-style single strchr allows you to "launder" a pointer-to-const into a pointer-to-non-const without a cast, and it's a hole in the const system. C++ (a) has overloading and (b) has a stricter type system than C, so it closes that hole.
If you want your real function updatePointer to work like strchr -- examine the data pointed to and compute a new value for the pointer, then you're in the same situation that strchr is. That's regardless of what it does with the new value (return it in the case of strchr, write it back in the case of updatePointer), because the issue is that you want the new pointer to have the same const-qualification as the input. You need to provide either const- and non-const overloads or a function template.
If you only need your real function updatePointer to move a pointer by a certain distance, regardless of the data pointed to, you could use std::advance instead.
What you wrote is a function taking a reference to a pointer to a const int. What you're asking for would be
updatePointer(int* const & i);
However this doesn't make much sense. Passing a reference to a pointer seems to imply that you intend to modify the pointer, but you cannot do it because it is declared const. As it is you'd obtain the same effect by just passing your pointer as in
updatePointer(int* i);
Found this
Copied here in case the link breaks in future:
The reasoning is a little awkward to comes to grips with. The main question is:
Since a "const int&" can be bound to an "int", why can't a "const int*&" be bound to a "int*"?
Basically, once you add a level of indirection (a pointer) then the rules change. With just a single level of indirection (as in a single *), the rule can be stated as:
A reference to a pointer to a cv-qualified type can be bound to anything of that same type whose cv-qualifications are less than or equal to that of the pointer (which is a reference).
(Read that a few times.)
So the reason a "const int*&" can't be bound to a "int*" is because "const int*" and "int*" are two different types (underlined part of the rule is broken).
error: passing 'const QByteArray' as 'this' argument of 'QByteArray& QByteArray::append(const QByteArray&)' discards qualifiers [-fpermissive]
since it is a convention to make objects const while passing as function arguments i have done it.
but now i am getting an error!!,
i dnt want to make the function constant as i have to convert data in qbyte array into short and then append it another array.
QByteArray ba((const char*)m_output.data(), sizeof(ushort));
playbackBuffer.append(ba);
I really need to pass this array into playbackbuffer;
It is giving me an error on playbackBuffer.append(ba);
please help
thanks in advance
This means you are calling a non-const member function on a const member. Presumably, your append function modifies the byte array. With a const reference, you shouldn't be modifying.
Basically what it says is that you're trying to append to a constant array.
If "append" does not change the object itself but just returns the two arrays appended, the method needs to be declared const to allow the call.
Consider this:
struct foo
{
void bar();
};
const foo f;
f.bar();
Here, in the call to bar(), the this pointer is &f. But bar() is not a const-function, so the type of this is foo*, which is incompatible with const foo*. (In other words, bar() says it might mutate the foo, but f says it's a non-mutablefoo.)
Either bar() needs to be marked as const (if it can), or f needs to not be const.
In your case, I'm going to assume you're using Qt and so cannot modify QByteArray (nor should you, since append is necessarily a non-const function), and instead suggest you get rid of the const on the object, which is preventing you from using the function.
So you are trying to call a non const function on a const object?
That's what passing a const xxx as 'this' argument would mean.
Since ultimately any member function really is
(Class * this, rest of arguments)
Either make your
QByteArray& QByteArray::append(const QByteArray&);
be
QByteArray& QByteArray::append(const QByteArray&) const;
(highly unlikely to solve anything) or just
QByteArray* pObj = const_cast<QByteArray*>(&your_obj)
if (pObj)
pObj->append(...
I'm really annoyed by const keyword these days, as I'm not quite familiar with it. I had a vector that stores all const pointers like vector<const BoxT<T> *> *Q_exclude, and in the constructor of another class, I need an element in this queue to be passed in as a parameter and assign it to a non-const member. My question is:
How do I assign a const variable to a non-const variable? I know this doesn't make sense because after all, a const is a const, and should not be changed by any mean. But that annoying member variable REALLY has to be changed during the process! I might also change the data type in the vector to be non-const, but that would be too much work. Or does anyone know how to avoid such situation?
You can assign a const object to a non-const object just fine. Because you're copying and thus creating a new object, constness is not violated.
Like so:
int main() {
const int a = 3;
int b = a;
}
It's different if you want to obtain a pointer or reference to the original, const object:
int main() {
const int a = 3;
int& b = a; // or int* b = &a;
}
// error: invalid initialization of reference of type 'int&' from
// expression of type 'const int'
You can use const_cast to hack around the type safety if you really must, but recall that you're doing exactly that: getting rid of the type safety. It's still undefined to modify a through b in the below example:
int main() {
const int a = 3;
int& b = const_cast<int&>(a);
b = 3;
}
Although it compiles without errors, anything can happen including opening a black hole or transferring all your hard-earned savings into my bank account.
If you have arrived at what you think is a requirement to do this, I'd urgently revisit your design because something is very wrong with it.
Changing a constant type will lead to an Undefined Behavior.
However, if you have an originally non-const object which is pointed to by a pointer-to-const or referenced by a reference-to-const then you can use const_cast to get rid of that const-ness.
Casting away constness is considered evil and should not be avoided. You should consider changing the type of the pointers you use in vector to non-const if you want to modify the data through it.
The actual code to cast away the const-ness of your pointer would be:
BoxT<T> * nonConstObj = const_cast<BoxT<T> *>(constObj);
But note that this really is cheating. A better solution would either be to figure out why you want to modify a const object, and redesign your code so you don't have to.... or remove the const declaration from your vector, if it turns out you don't really want those items to be read-only after all.
Leaving this here for myself,
If I get this error, I probably used const char* when I should be using char* const.
This makes the pointer constant, and not the contents of the string.
const char* const makes it so the value and the pointer is constant also.
void SomeClass::changeASettingAndCallAFunction() const {
someSetting = 0; //Can't do this
someFunctionThatUsesTheSetting();
}
Another solution is to call said function in-between making edits to variables that the const function uses. This idea was what solved my problem being as I was not inclined to change the signature of the function and had to use the "changeASettingAndCallAFunction" method as a mediator:
When you call the function you can first make edits to the setting before the call, or (if you aren't inclined to mess with the invoking place) perhaps call the function where you need the change to the variable to be propagated (like in my case).
void SomeClass::someFunctionThatUsesTheSetting() const {
//We really don't want to touch this functions implementation
ClassUsesSetting* classUsesSetting = ClassUsesSetting::PropagateAcrossClass(someSetting);
/*
Do important stuff
*/
}
void SomeClass::changeASettingAndCallAFunction() const {
someFunctionThatUsesTheSetting();
/*
Have to do this
*/
}
void SomeClass::nonConstInvoker(){
someSetting = 0;
changeASettingAndCallAFunction();
}
Now, when some reference to "someFunctionThatUsesTheSetting" is invoked, it will invoke with the change to someSetting.