Yesterday I came across a function like this in my team's code, using the jsoncpp library:
#include <json/value.h>
Json::Value makeList() {
Json::Value list(Json::arrayValue);
list.append(new Json::Value(true));
return list;
}
It came to my attention because using new
in the call to list.append
leaks some memory, which can be fixed by simply dropping new
. However, in debugging this I realized that Json::Value::append
takes either a const Json::Value&
or a Json::Value&&
. C++ does not implicitly convert pointers to references, so a Json::Value*
should not be implicitly converted into either of these.
To confirm this, I wrote my own short example:
#include <iostream>
class Foo {
public:
int x = 4;
};
void printValue(const Foo& f) { std::cout << "The value is " << f.x << ".\n"; }
void printValue(Foo&& f) { std::cout << "The value is " << f.x << ".\n"; }
int main() {
printValue(new Foo());
}
And indeed, this results in a compilation error:
own-example.cpp:12:5: error: no matching function for call to 'printValue'
printValue(new Foo());
^~~~~~~~~~
own-example.cpp:8:6: note: candidate function not viable: no known conversion from 'Foo *' to 'const Foo' for 1st argument; dereference the argument with *
void printValue(const Foo& f) { std::cout << "The value is " << f.x << ".\n"; }
^
own-example.cpp:9:6: note: candidate function not viable: no known conversion from 'Foo *' to 'Foo' for 1st argument; dereference the argument with *
void printValue(Foo&& f) { std::cout << "The value is " << f.x << ".\n"; }
^
So, why does the code I found calling Json::Value::append
compile, while the toy example does not?
Json::Value(new Json::Value())
compiles because
bool x = new Json::Value();
compiles thanks to C++ rules allowing implicit conversion from a pointer to bool
, andJson::Value
has a constructor overload that takes a bool
.