Issue
Using Netbeans 8.2 on Linux and GCC 8.1, unique_ptr::operator->()
gives an erroneous warning
Unable to resolve template based identifier {var}
and more importantly will not autocomplete member names.
Code compiles and runs just fine, and amazingly, the autocomplete still works with no warnings if a shared_ptr
is used instead. I have no idea how that is possible. Here is a problematic example, for reference
#include <iostream>
#include <memory>
struct C { int a;};
int main () {
std::unique_ptr<C> foo (new C);
std::shared_ptr<C> bar (new C);
foo->a = 10; //Displays warning, does not auto-complete the members of C
bar->a = 20; //No warning, auto-completes members of C
return 0;
}
I've tried the following to resolve this issue with no luck:
- Code Assistance > Reparse Project
- Code Assistance > Clean C/C++ cache and restart IDE
- Manually deleting cache in
~/.cache/netbeans/8.2
- Looking through View > IDE Log for anything that may help
- Setting both the C and C++ compilers to C11 and C++11 in project properties
- Changing the pre-processing macro __cplusplus to both 201103L and 201402L
- Creating a new Netbeans project and trying the above
- A large variety of permutations of the above options in different orders
Again, everything compiles and runs just fine, it's just Code Assistance that is giving me an issue. I've run out of things that I've found in other stack overflow answers. My intuition tells me that shared_ptr
working and unique_ptr
not working is helpful, but I don't know enough about C++ to utilize that information. Please help me, I need to get back to work...
Edit 1
This stack overflow question, although referencing Clang and the libc++ implementation, suggests that it may be an implementation issue within GCC 8.1's libstdc++ unique_ptr
.
Solution
TLDR Method 1
Add a using pointer = {structName}*
directive in your structure fixes code assistance, and will compile and run as intended, like so:
struct C { using pointer = C*; int a;};
TLDR Method 2
The answer referenced in my edit does in fact work for libstdc++ as well. Simply changing the return type of unique_ptr::operator->()
from pointer
to element_type*
will fix code assistance, compile and run as expected (the same thing can be done to unique_ptr::get()
). However, changing things in implementations of the standard library worries me greatly.
More Information
As someone who is relatively new to c++ and barely understands the power of template specializations, reading through unique_ptr.h
was scary, but here is what I think is messing up Netbeans:
- Calling
unique_ptr::operator->()
callsunique_ptr::get()
unique_ptr::get()
calls the private implementation's (__unique_ptr_impl
) pointer function__unique_ptr_impl::_M_ptr()
. All these calls return the__unique_ptr_impl::pointer
type.- Within the private implementation, the type
pointer
is defined within an even more private implementation_Ptr
. The struct_Ptr
has two template definitions, one that returns a raw pointer to the initial template variable ofunique_ptr
, and the second that seems to strip any reference off this template variable, and then find it's type namedpointer
. I think that this is where Netbeans messes up.
So my understanding is when you call unique_ptr<elementType, deleterType>::operator->()
, it goes to __unique_ptr_impl<elementType, deleterType>
, where the internal pointer type is found by stripping elementType
of any references and then getting the type named dereferenced(elementType)::pointer
. So by including the directive using pointer =
, Netbeans gets what it wants in finding the dereferenced(elementType)::pointer
type.
Including the using
directive is entirely superficial, evidenced by the fact that things will compile without it, and by the following example
#include <memory>
#include <iostream>
struct A{
using pointer = A*;
double memA;
A() : memA(1) {}
};
struct B {
using pointer = A*;
double memB;
B() : memB(2) {}
};
int main() {
unique_ptr<A> pa(new A);
unique_ptr<B> pb(new B);
std::cout << pa->memA << std::endl;
std::cout << pb->memB << std::endl;
};
outputs
1
2
As it should, even though in struct B contains using pointer = A*
. Netbeans actually tries to autocomplete B->
to B->memA
, further evidence that Netbeans is using the logic proposed above.
This solution is contrived as all hell but at least it works (in the wildly specific context that I've used it) without making changes to implementations of stl. Who knows, I'm still confused about the convoluted typing system within unique_ptr
.
Answered By - TermVelQ
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)