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.
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->() calls unique_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 of unique_ptr, and the second that seems to strip any reference off this template variable, and then find it's type named pointer. 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.
Related
In my C++ program I have a class, in some methods of which there are same routines happen, such as opening streams for reading/writing to files, parsing files, determining mime types, etc. Same routines are also used in constructor. To make methods more compact and avoid typing same code multiple times I split these routine operations into private methods for using inside the class only. However, some of these private methods depend on the result of the others, so that calling these methods in wrong order could lead in pretty bad consequences.
Just a stupid example:
class Example
{
public:
Example(int x);
~Example() {}
//...
//...
protected:
private:
int a;
int b;
bool c;
void foo_();
void bar_();
//...
//...
};
Example::Example(int x) : a(x)
{
foo_();
bar_();
}
void Example::foo_()
{
if (a == 0)
{
b = 10;
}
else
{
b = a * 2;
}
}
void Example::bar_()
{
if (b == 0)
{
c = false;
}
else
{
c = true;
}
}
As can be seen from the above example, calling bar_() before foo_() in constructor will lead in undefined behavior because b has not been yet initialized. But should I bother about such nuances if I am definitely sure that I am using these private methods correctly inside the class, and they can never be used outside the class?
Not to mention that what you did is the recommended way! Whenever you have multiple different operations inside a function, the standard way is to separate the function into multiple functions. In your case, the user does not need those functions, so making them private was the best you could do! When it comes to the part where "I need to call them in a specific order", its entirely fine if the code needs calls in a particular order. I mean, its only logical to call foo after bar is the former depends on the result of the later. It's not much different than when you need to assign memory to int* p before using it as an array. Although, as #Basil and many others have explained, be sure to document your code correctly
calling bar_() before foo_() in constructor will lead in undefined behavior because b has not been yet initialized
As a rule of thumb, I always explicitly initialize all member fields in a constructor (in particular those having a scalar type like pointers or numbers, e.g. your a,b,c inside class Example). Advantage: the behavior of your program is more reproducible. Disadvantage: the compiled code might run useless initialization (but clever optimizing compilers would remove them).
If you compile with GCC, use it as g++ -Wall -Wextra -g. It usually gives you useful warnings.
For a large C++ project, consider documenting your coding rules (in a separate written document, on paper, distributed to all developers in your team) and checking some of them with your GCC plugin. See also the DECODER project and the Bismon static source code analyzer, and the Clang static analyzer (all of GCC, Bismon and Clang analyzer are open source, you can improve their source code).
In some cases some C++ code is generated. See GNU bison, ANTLR, RefPerSys, FLTK, Qt as examples of software projects generating C++ code or providing code generators emitting C++ code. On x86/64 PCs, you could generate machine code at runtime with ASMJIT or libgccjit, and call that code thru function pointers (on Linux see also dlopen(3), dlsym(3) and the C++ dlopen minihowto...). If your software project has C++ code generators (e.g. using GPP), you can ensure that the generated code respects some of your coding conventions and invariants. Be however aware of Rice's theorem.
If you debug with GDB, read about its watch command and watchpoints.
I am also aware of the C++ rule of five.
I'm working on a project in Visual Studio that includes a "portable" menu GUI for anyone who wants it in their own work. Since I keep getting the C2797 compiler error, I can't use structs at all since nothing has helped and I use classes a lot.
Basically, I can't use structs, even though it's the most important part of my project.
Menu.h:
struct menuItem
{
const char *name;
bool value;
};
Test.h:
#include "Menu.h"
class Test
{
public:
menuItem dummy = { "Useless option", false }; // <--This is where I get C2797
};
Again, this won't compile, but if I use this exact code in a simple C++ console app, it works flawlessly on all compiler versions.
If you need more details, when I use structs outside of classes, I get C4430 intertwined with C2440 and C2065. (And adding cstdint doesn't help that) If I try using the exact same struct in the closest situation possible in a different project, it compiles with all compiler versions just fine.
For the people who might think that it's because of the VS 2013 compiler (Which I'm using), I've already switched between newer and older versions between all of my projects and it made no difference.
For the other people who didn't see my details in the comments: Pastebin of errors in the console
The fix, as the documentation for the error states, is to explicitly construct the struct on the RHS of the assignment rather than trying to get the compiler to deduce the type of the brace-initializer (which it is unable to do correctly). Like this:
class Test
{
public:
menuItem dummy = menuItem{ "Useless option", false }; // Note the extra menuItem
};
I believe it's because you're not allowed to initialize variables inside the public: unless they are static. Maybe if you try
public:
static const menuItem={"Useless option", false }; // might work
I'm getting an ICE on Visual Studio 2015 CTP 6. Unfortunately, this is happening in a large project, and I can't post the whole code here, and I have been unable to reproduce the problem on a minimal sample. What I'm hoping to get is help in constructing such a sample (to submit to Microsoft) or possibly illumination regarding what's happening and/or what I'm doing wrong.
This is a mock-up of what I'm doing. (Note that the code I'm presenting here does NOT generate an ICE; I'm merely using this simple example to explain the situation.)
I have a class A which is not copyable (it has a couple of "reference" members) and doesn't have a default constructor. Another class, B holds an array of As (plain C array of A values, no references/pointers) and I'm initializing this array in the constructor of B using uniform initialization syntax. See the sample code below.
struct B;
struct A
{
int & x;
B * b;
A (B * b_, int & x_) : x (x_), b (b_) {}
A (A const &) = delete;
A & operator = (A const &) = delete;
};
struct B
{
A a [3];
int foo;
B ()
: a {{this,foo},{this,foo},{nullptr,foo}} // <-- THE CULPRIT!
, foo (2)
{ // <-- This is where the compiler says the error occurs
}
};
int main ()
{
B b;
return 0;
}
I can't use std::array because I need to construct the elements in their final place (can't copy.) I can't use std::vector because I need B to contain the As.
Note that if I don't use an array and use individual variables (e.g. A a0, a1, a2;, which I can do because the array is small and fixed in size) the ICE goes away. But this is not what I want since I'll lose ability to get to them by index, which I need. I can use a union of the loose variables over the array to solve my ICE problem and get indexing (construct using the variables, access using the array,) but I think that would result in "undefined behavior" and seems convoluted.
The obvious differences between the above sample and my actual code (aside from the scale) is that A and B are classes instead of structs, each is declared/defined in its own source/header file pair, and none of the constructors is inline. (I duplicated these and still couldn't reproduce the ICE.)
For my actual project, I've tried cleaning the built files and rebuild, to no avail. Any suggestions, etc.?
P.S. I'm not sure if my title is suitable. Any suggestions on that?!?!
UPDATE 1: This is the compiler file referenced in the C1001 fatal error message: (compiler file 'f:\dd\vctools\compiler\utc\src\p2\main.c', line 230).
UPDATE 2: Since I had forgotten to mention, the codebase compiles cleanly (and correctly) under GCC 4.9.2 in C++14 mode.
Also, I'm compiling with all optimizations disabled.
UPDATE 3: I have found out that if I rearrange the member data in B and put the array at the very end, the code compiles. I've tried several other permutations and it sometimes does compile and sometimes doesn't. I can't see any patterns regarding what other members coming before the array make the compiler go full ICE! (being UDTs or primitives, having constructors or not, POD or not, reference or pointer or value type, ...)
This means that I have sort of a solution for my problem, although my internal class layout is important to me and this application, I can tolerate the performance hit (due to cache misses resulting from putting some hot data apart from the rest) in order to get past this thing.
However, I still really like a minimal repro of the ICE to be able to submit to Microsoft. I don't want to be stuck with this for the next two years (at least!)
UPDATE 4: I have tried VS2015 RC and the ICE is still there (although the error message refers to a different internal line of code, line 247 in the same "main.c" file.)
And I have opened a bug report on Microsoft Connect.
I did report this to Microsoft, and after sharing some of my project code with them, it seems that the problem has been tracked down and fixed. They said that the fix will be included in the final VC14 release.
Thanks for the comments and pointers.
Intellisense is working very badly with my VS...
When I'm coding in C++ it works 100% fine, until I start using templates, then it just stops working completely, stops detecting errors and don't auto-complete in all cases.
I'm inclined to believe it has to do with something I have done with my code that broke it.
So I started by creating a class with a struct in it:
template<typename T>
class List<T>
{
private:
struct Node
{
T value;
Node* next;
Node* previous;
};
Node* First;
Node* Last;
...
};
later, I declare some additional functions:
template<typename T>
inline T List::First()
{
return First;
}
so far so good, intellisense is working 100% fine, but if I try to do first-> it won't work, VS won't tell give me any options (ctrl + space doesn't work).
also, if I type some nonsense it won't tell me it's wrong:
sdkjgisjdga->vsrsiib = 123jgi;
I don't really know what to do in order to fix this.
Thank you for your time and efforts.
PS: I already tried to reset the configurations.
EDIT: Forgot to say that if i don't use templates in my .h file then intellisense works correctly.
Templates need to be instantiated before you can definitively say what they contain. For example, your First-> snippet points to a List<T>::Node, and that is obviously dependent on the exact T.
Sure, Intellisense in this simple case could unambiguously list the members by just substituting T==int for a moment. But consider what's worse: Intellisense not knowing the members (like now) or Intellisense mis-guessing in the hard cases where you need it most?
I am a bit late with this answer, and maybe the OP is not working on this code anymore, but I think this may still help someone who is searching templates and IntelliSense.
One thing you can try -- if you want to be able to see your typos and errors as you type, but if you want your code to be template-able -- is using an #if-#else-#endif:
#if MY_USE_TEMPLATES
template <typename T>
#else
typedef [**your-test-type-here**] T;
#endif
class List {
... your code here ...
}
In Visual Studio 2015 this seems to work. You can define MY_USE_TEMPLATES to be 0 (using a #define), develop your code with IntelliSense and auto-complete, etc. (so you make less mistakes), and then change the MY_USE_TEMPLATES to 1 when you are ready to test or compile with actual template code.
While you have MY_USE_TEMPLATES turned on, code that references your List will result in error (i.e., code like 'List myList'), and you can resolve that with an extra dummy 'template' inside the #else statement. However, the good thing about leaving the #else clause without an extra 'template' is: the error you get when referencing your List may serve you as a reminder to turn on MY_USE_TEMPLATES before testing the code, reducing the probability of a bug. (Experience suggests that it is easy to forget when handling a lot of things and large projects ...)
Do be careful about using multiple such type definitions, however: the 'typedef ... T' can only be safely used once for that name "T"; while you can use 'typedef ... TYPE1' for one class and 'typedef ... TYPE2' for another, you cannot safely use the same type name for different types unless you put the different type names into separate namespaces. (I tried this in Visual Studio 2015.)
I'm working on this VST convolution plugin (Windows 7 64bit, VS2010) and I decided to try the Intel c++ compiler. I was in the process of optimizing the algorithm so I had a backup project in case of any screw ups and one I was doing experiments on. Both projects would compile and run with no problems. After installing the Intel compiler though the project I was experimenting on would cause a heap corruption error, so I start debugging to track down the problem but I can't find the line of code that causes it since the heap corruption error is not triggered during execution but after the termination of the DLL (there are also no access violations showed by the debugger).
At this point I start cutting out parts of the code to see if I can isolate the problem and I discover (obviously) that it was the class I was eperimenting on. Now here comes the weird part: I can change the code inside the methods but as soon as I add a variable to the backup class (the one that works fine), even an int, I get the heap corruption error, just a decleared and never referenced variable is enough.
This is the class CRTConvolver:
class CRTConvolver
{
public:
CRTConvolver();
~CRTConvolver();
bool Init(float* Imp, unsigned ImpLen, unsigned DataLen);
void doConv(float* input);
Buff Output;
int debug_test;
private:
void ZeroVars();
int Order(int sampleFrames);
template <class T> void swap ( T& a, T& b );
Buff *Ir_FFT,*Input_FFT,Output2,Tmp,Prev,Last;
float *Tail;
unsigned nBlocks,BlockLen,Bl_Indx;
IppsFFTSpec_R_32f* spec;
};
that "int debug_test;" makes the difference between a perfectly working VST module and a program that crashes on initialization from Cubase.
always for debugging purposes here are destr and constr:
CRTConvolver::CRTConvolver()
{
//IppStatus status=ippInit();
//ZeroVars();
}
CRTConvolver::~CRTConvolver()
{
//Init(NULL,NULL,NULL);
}
Here is what class Buff looks like:
class Buff {
public:
Buff();
Buff(unsigned len);
~Buff();
float* buff;
unsigned long length;
private:
void Init(unsigned long len);
void flush();
friend class CRTConvolver;
}
Buff::Buff()
{
length=NULL;
buff=NULL;
}
Buff::~Buff()
{
// flush();
}
basically this class if created and destructed does absolutely nothing, it just contains the length and buff variables. If I also bypass those two variable initializations the heap error goes away.
The software crashes on simple construction and subsequent destruction of the class CRTConvolver even though all it does is nothing, this is the part that really doesn't make sense to me...
As a side note, I create my CRTConvolver class like this:
ConvEng = new CRTConvolver[NCHANNELS];
If I declare it like this instead:
CRTConvolver ConvEng[NCHANNELS];
I get a stack corruption error around variable ConvEng.
If I switch back to Microsoft compiler the situation stays the same even when compiling and running the exact same version that could run without errors before....
I can't stress enough the fact that before installing the Intel compiler everything was running just fine, is it possible that something went wrong or there's an incompatibility somewhere ?
I'm really running out of ideas here, I hope someone will be able to help.
thanks
Going to guess, since the problem is most likely undefined behavior, but in some other place in your code:
Obey the rule of three. You should have a copy constructor and assignment operator. If you're using std containers, or making copies or assignments, without these you run into trouble if you delete memory inside the destructor.
It looks to me that the CRTConvolver default constructor (used in creating an array) is writing to memory it doesn't own. If the Intel compiler has different class layout rules (or data alignment rules), it might be unmasking a bug that was benign under the Microsoft compiler's rules.
Does the CRTConvolver class contain any instances of the Buff class?
Updated to respond to code update:
The CRTConvolver class contains four instances of Buff, so I suspect that is where the problem lies. It could be a version mismatch -- the CRTConvolver class thinks that Buff is smaller than it really is. I suggest you recompile everything and get back to us.