Compiler errors with incorrect use of nullptr - c++

I am trying the solution provided in this SO Q/ACompiler error while using shared_ptr with a pointer to a pointer and I am not able to use the solution provided in a proper way. I still get compilation errors on Ubuntu 18.04 with g++ version 7.3
Here is my minimum complete verifiable example to reproduce the problem
test.h
# include <memory>
using std::shared_ptr;
using std::unique_ptr;
struct DataNode
{
shared_ptr<DataNode> next;
} ;
struct ProxyNode
{
shared_ptr<DataNode> pointers[5];
} ;
struct _test_
{
shared_ptr<shared_ptr<ProxyNode>> flane_pointers;
};
test.cpp
#include <stdint.h>
#include "test.h"
shared_ptr<DataNode> newNode(uint64_t key);
shared_ptr<ProxyNode> newProxyNode(shared_ptr<DataNode> node);
struct _test_ test1;
int main(void)
{
test1.flane_pointers(nullptr);
shared_ptr<DataNode> node = newNode(1000);
}
shared_ptr<ProxyNode> newProxyNode(shared_ptr<DataNode> node) {
shared_ptr<ProxyNode> proxy(new ProxyNode());
return proxy;
}
shared_ptr<DataNode> newNode(uint64_t key) {
shared_ptr<DataNode> node(new DataNode());
return node;
}
This is the error I get
test.cpp: In function ‘int main()’:
test.cpp:11:31: error: no match for call to ‘(std::shared_ptr<std::shared_ptr<ProxyNode> >) (std::nullptr_t)’
test1.flane_pointers(nullptr);
^
What else have you tried ?
I tried initializing the nullptr in the header file as well
struct _test_
{
shared_ptr<shared_ptr<ProxyNode>> flane_pointers(nullptr);
};
But that did not work either. Where am I going wrong ?
My Goal
All I am trying to do is the following - I am trying to initialize flane_pointers which is a vector of pointers to a nullptr. The declaration has been made in a header file as to what type it is and I am trying to initialize it in a .cpp file. While doing that I get the above compilation errors.
flane_pointers(nullptr)
UPDATE
Could any of the answers explain whether the initialization provided in this Compiler error while using shared_ptr with a pointer to a pointer correct or not ?
std::shared_ptr<std::shared_ptr<ProxyNode> > ptr2ptr2ProxyNode(nullptr);
To me (and I am a newbie to C++) that initialization looks like a function call as well. Is that incorrect ?

On this line:
test1.flane_pointers(nullptr);
You're trying to call flane_pointers as though it were a member function. shared_ptr can't be called like a function, so you get the compiler error.
If you want to initialize flane_pointers, you can just assign to it:
test1.flane_pointers = nullptr;
Or alternatively, you could do the assignment when you create test1:
// Initialize test1 with a nullptr
_test_ test1{nullptr};

If your intent is to initialize flane_pointers to nullptr, you should use initialization of the below form:
shared_ptr<shared_ptr<ProxyNode>> flane_pointers = nullptr;
in struct _test_
or
test1.flane_pointers = nullptr;
in main.
The other form of initialization you are trying to do is interpreted as a function call in main and as a function declaration in struct _test_.
In the linked post,
std::shared_ptr<std::shared_ptr<ProxyNode> > ptr2ptr2ProxyNode(nullptr);
is in main and can only be interpreted as a variable declaration and not a function call because it does not have a function call syntax as the variable is preceded by the type std::shared_ptr >.
To avoid confusion, it is better (from C++11 onwards) to declare and initialize variables with the brace-enclosed initializer {}.

The line
test1.flane_pointers(nullptr);
is treated a function call. That's the source of the error. Use assignment instead.
test1.flane_pointers = nullptr;
And
shared_ptr<shared_ptr<ProxyNode>> flane_pointers(nullptr);
is not a valid form of in-member initialization. You may use
shared_ptr<shared_ptr<ProxyNode>> flane_pointers{nullptr};
or
shared_ptr<shared_ptr<ProxyNode>> flane_pointers = nullptr;

Related

Error: expected constructor, destructor, or type conversion before '*' token|

I am trying to implement a Binary Search Tree. The code isn't complete, but I built it anyways to see what possible errors I would get.
Here is the code for it:
BST.h
class BST {
public:
struct node
{
//All nodes must be able to point to left and right
int key; //All nodes can hold a key value
node* left; //All nodes have a left pointer
node* right;//All nodes have a right pointer
};
node* root; //References the very top of the tree
public:
BST(); //Constructor that initializes each time instance is called
node* CreateLeaf(int key);
};
BST.cpp
#include<iostream>
#include<cstdlib>
#include "BST.h"
using namespace std;
BST::BST()
{
root = NULL;
}
node* BST::CreateLeaf(int key) //Causing errors
{
node* n = new node;
n->key = key;
n->left = NULL;
n->right = NULL;
return n;
}
main.cpp
#include <iostream>
#include <cstdlib>
#include "BST.cpp"
using namespace std;
int main()
{
return 0;
}
This gives the error:
Error: expected constructor, destructor, or type conversion before '*' token
In the BST.cpp file, if I declare the CreateLeaf() function as:
typedef node* BST::CreateLeaf(int key)
the error changes to:
Error: expected initializer before '*' token
Now, with common sense, since I am declaring the CreateLeaf function outside the class, I do this:
BST::node* BST::CreateLeaf(int key)
Now the error becomes:
Error: In function BST: multiple definition of `BST::BST()'
I am using the CodeBlocks IDE on Windows 10.
EDIT:
I removed the .cpp file and declared all functions inside the header file (and included header file in the main function). Now it is compiling. But it would be great if someone could let me know why the error was occurring in the first place.
In the declaration
node* BST::CreateLeaf(int key)
… the name node is not known to the compiler, because it's defined within the BST class and it's here used outside of that class.
One simple fix is to use the newer trailing return type syntax:
auto BST::CreateLeaf(int key)
-> node*
Here the compiler knows that the declaration belongs to the BST class, at the point where it encounters node.
Alternatively you can qualify the name,
BST::node* BST::CreateLeaf(int key)
… but that can get ugly fast, especially with template code.
In other news, the
#include "BST.cpp"
… in file main.cpp is ungood practice. One practical reason is that in an IDE project this may cause that code to be compiled twice: one compilation of BST.cpp, and one compilation of that same code as included in main.cpp.
Instead just compile BST.cpp separately.
Or, design it as a header file module (mainly this involves declaring functions as inline).
Outside the class declaration you need to prefix the scope to node:
BST::node* BST::CreateLeaf(int key) {
// ^^^^^ ...
}
Also you shouldn't include .cpp files. Include the header, and compile and link the .cpp files separately.

"Expected a type specifier" error when creating an object of a class inside another class declaration

I have a class called scratch and have used scratch.h to declare it.
Now I have another class called scratch2 under scratch2.h and want to create an object of scratch as a shared pointer.
This is the syntax I used inside scratch2 class declartion:
std::shared_ptr<scratch> newObject(new scratch());
But I am getting this error: Error: Expected type specifier
So I tried this instead:
std::shared_ptr<scratch> newObject2 = std::make_shared<scratch>();
which works fine. Can anyone please tell me why the first one isn't working?
My scratch.h code:
#ifndef _SCRATCH_
#define _SCRATCH_
#include <iostream>
class scratch {
private:
int _a;
float _b;
std::string _s;
public:
scratch();
scratch(int a, float b, std::string n);
~scratch();
};
#endif
and my scratch2.h:
#ifndef _SCRATCH_2_
#define _SCRATCH_2_
#include "scratch.h"
#include <memory>
class scratch2 {
std::shared_ptr<scratch> newObject(new scratch()); // Expected a type specifier error occurs here
std::shared_ptr<scratch> newObject2 = std::make_shared<scratch>(); // works fine here
};
#endif
Because in the context of declaring class members:
std::shared_ptr<scratch> newObject(new scratch());
This initially looks to the compiler as a class method declaration. C++'s syntax is very complicated. You can look at the entire declaration and understand what it's trying to do, but the compiler is parsing keywords one keyword at a time, and sees this:
type name( ...
inside a class declaration, and this starts to look like a class method declaration, and that's what the compiler tried to parse, and failed.
The formal specification of the C++ language spills a lot of ink on the subject of how things should be declared, mindful of the current state of compiler technology.
You need to work with the compiler, and use an alternate syntax that's unambiguous:
std::shared_ptr<scratch> newObject = std::shared_ptr<scratch>(new scratch());
Verified with gcc 5.3
Inside of a class definition, there are only two ways you're allowed to initialize your members. You can use = and you can use {}. You are not allowed to use ():
struct foo {
int x = 4; // OK
int y{7}; // OK
int z(12); // error
};
Admittedly, the compiler error in this case is extremely unhelpful.

constructing a pair(string, *node) to insert into an unordered_map

typedef unordered_map<string, relationNode*> relationMap;
using relation_entry = relationMap::value_type;
void insertNode(string category, relationNode* node) {
relation_entry insertPair =
make_pair<string, relationNode*>(category, node);
}
causes an error of "cannot convert 'category' (type 'std::string(aka std::basic_string(char))') to type 'std::basic_string(char)&&"
and an error of "cannot convert 'node' (type 'relationNode*') to type 'relationNode*&&".
I was planning to make the pair then insert it into a unordered_map.
I am using "g++ -g -O0 -Wall -Wextra -std=gnu++11" to compile the code. Any help will be greatly appreciated.
Just write:
relation_entry insertPair =
make_pair(category, node);
This will work and be more concise (in fact, that's the reason you use std::make_pair instead of calling the constructor directly in the first place).
You should know that this is a backward-compatibility issue with C++11. Consider this piece of C++98 code (I replaced unordered_map with map and using with typedef):
#include <map>
#include <string>
using namespace std; // just for testing
struct relationNode {};
typedef map<string, relationNode*> relationMap;
typedef relationMap::value_type relation_entry;
void insertNode(string category, relationNode* node) {
relation_entry insertPair =
make_pair<string, relationNode*>(category, node);
}
int main() {
}
Go to http://cpp.sh/ and try to compile it. You will see that it compiles fine in C++98 mode but not in C++11 and C++14 modes.
For a detailed explanation of the issue, see C++11 make_pair with specified template parameters doesn't compile
Bottom line: Don't specify redundant type arguments and you'll be fine.

Incomplete types with Clang compiling c++11 code

As this website shows, following code will not be supported in Clang using C++11:
class Node {
vertex<Node> children;
};
An error will occur:
field has incomplete type 'Node'
But such code is supported in C++98 and other compilers such as gcc in C++11.
I know I can use
vertex<Node*>
instead, but at present I have some incompatibility issue with old code in C++98.
My question is, (1) can I compile such code using Clang in C++11? (2) I think a tree structure does inevitably need definition like above, without support of such feature, how can I realize such tree structure?
update:
Sorry for forgetting to give definition of vertex, What about the following code:
class Node {
vector<Node> children;
};
Just change vertex into a container vector. It is not valid in Clang with C++11, but ok with other compilers and with C++98.
update again:
It seems vector works OK..but list fails
class Node {
std::list<Node> children;
};
update again:
Following is my code:
#include <list>
using namespace std;
class Node {
list<Node> nodes;
};
int main(int argc, char const *argv[])
{
return 0;
}
or simpler:
#include <list>
class Node {
std::list<Node> nodes;
};
int main() {}
I'm using Clang 4.0 and using the following command to compile:
clang++ -std=c++11 -stdlib=libc++ test.cpp
The error is
/usr/bin/../lib/c++/v1/list:212:9: error: field has incomplete type 'Node'
If it does not compile, it means that vertex attempts to use Node in a way that requires it to be completely defined. Most of the time, this implies (for generic code) using the size of the T parameter:
either explicitly (sizeof(T))
or implicitly template <typename T> struct vertex { T data[3]; }; is using the size of T to compute the layout of the type
Another (possible) issue, is relying on methods of T for some template instantiation; however this is much rarer.
You can avoid this requirement by changing the definition of vertex. Not knowing what it is though, we won't be able to get much more specific...

C code does not work when coded like C++

Hello Developers! I am learning algorithms from Algorithms Design Manual Book by Skiena. There I have the following code:
#include <stdio.h>
#include <stdlib.h>
typedef int item_type;
typedef struct{
item_type item;
struct list* next;
}list;
void insert_list(list **l, item_type x){
list *p;
p = malloc(sizeof(list));
p->item = x;
p->next = *l;
*l = p;
}
int main(){
return 0;
}
It gives me Warning when compiled:
gcc -Wall -o "test" "test.c" (in directory:
/home/akacoder/Desktop/Algorithm_Design_Manual/chapter2) test.c: In
function ‘insert_list’: test.c:15: warning: assignment from
incompatible pointer type Compilation finished successfully.
But when I rewrite this code as C++:
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
typedef int item_type;
typedef struct{
item_type item;
struct list* next;
}list;
void insert_list(list **l, item_type x){
list *p;
p = malloc(sizeof(list));
p->item = x;
p->next = *l;
*l = p;
}
int main(){
return 0;
}
It gives the following:
g++ -Wall -o "chapter2" "chapter2.cpp" (in directory:
/home/akacoder/Desktop/Algorithm_Design_Manual/chapter2)
chapter2.cpp:15: error: conflicting declaration ‘typedef struct list
list’ chapter2.cpp:14: error: ‘struct list’ has a previous declaration
as ‘struct list’ chapter2.cpp: In function ‘void insert_list(list**,
item_type)’: chapter2.cpp: In function ‘void insert_list(list**,
item_type)’: chapter2.cpp:19: error: invalid conversion from ‘void*’
to ‘list*’
Can anyone explain why it is so? And How can I rewrite it in C++?
This is because c++ is stricter than c with respect to type conversions.
There are host of other errors in your code. Please note that just putting a c source code, renaming the file as .cpp & compiling using g++ does not make a c source code as c++.
If you are writing a program in c++ please use new & not malloc, doing so you do not need to explicitly type cast as in case of malloc.
Your problem in both cases is in the struct definition: struct list *next doesn't refer to the struct you are in the process of declaring. Try this instead:
typedef struct list {
item_type item;
struct list* next;
} list;
In addition, in C++ you must cast the void * returned by malloc to the appropriate pointer type (list *), C++ is stricter about these things. Also, BTW, in C++ you can leave off the typedef completely if you want.
The reason for the differing error messages is a difference in the languages.
In C, the compiler knows that struct list * is a pointer to a struct, so it doesn't need to complain that it doesn't actually know what a "struct list" is yet. Later, though, when you try to assign this "struct list *" from a pointer of type "list *" (the type of which is "pointer to an anonymous struct"), it complains about the mismatch.
In C++, a "struct" declaration is more or less equivalent to a "class" declaration (the major difference is in the default visibility of members). Among other things, this means that structs in C++ are more or less automatically typedefed. So when the compiler sees "struct list *next", it takes it as a forward declaration of a class named "list"; then when it finishes the statement and processes the typedef, throws an error because you're trying to typedef something to an identifier that is already (forward-)declared as something else. Then it issues further errors because it doesn't actually know what "list" might be, due to the earlier error.
C++ does not allow arbitrary pointer conversions, while C does. But since this is not considered good style, the compiler emits a warning.
Just add a cast and it will solve both messages:
p = (list*)malloc(sizeof(list));
Or if you want to be C++ only:
p = new list;
But then, you should declare constructors and such, also.
This is explained in this link.
Quote:
Gotcha for a C++ programmer using C
Structs and Enums
You have to
include the struct keyword before the name of the struct type to
declare a struct: In C++, you could do this
struct a_struct {
int x; };
a_struct struct_instance;
and have a new instance of a_struct called struct_instance. In C,
however, we have to include the struct keyword when declaring
struct_instance:
struct a_struct struct_instance;
In fact, a similar situation also holds for declaring enums: in C, you
must include the keyword enum; in C++, you don't have to. As a side
note, most C programmers get around this issue by using typedefs:
typedef struct struct_name {
/* variables */ } struct_name_t;
Now you can declare a struct with
struct_name_t struct_name_t_instance;
But there is another gotcha for C++ programmers: you must still use
the "struct struct_name" syntax to declare a struct member that is
a pointer to the struct.
typedef struct struct_name {
struct struct_name instance;
struct_name_t instance2; /* invalid! The typedef isn't defined
yet */ } struct_name_t;
You need to change this class:
typedef struct{
item_type item;
struct list* next;
}list;
to this:
struct list {
item_type item;
list* next;
};
Explanation: in the first example, you have anonymous structure, inside which struct list is forward declared. So when compiler sees typedef on the next line it finds a name collision, because typedef is not the same as struct declaration in C++.
Since what you're doing is really defining a struct and then creating an alias with the typedef I think it's more readable to do this in the C case:
typedef struct list_ {
item_type item;
struct list_* next;
} list;
Use the following code
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
typedef int item_type;
struct list{
item_type item;
list* next;
};
void insert_list(list **l, item_type x){
list *p;
p = (list*)malloc(sizeof(list));
p->item = x;
p->next = *l;
*l = p;
}
int main(){
return 0;
}
What C only warns against, C++ is likely to consider an error.
It's a programming cultural thing. C was very forgiving in not enforcing it's typing system. C++ is still quite forgiving, but you're doing something in C that even C++ won't forgive.
When you malloc that block of memory, cast it to a pointer to a list. That will covert the address (pointer) to a pointer of the right type.
Without that cast, you could have malloc'd the size of anything, and there's no telling if it was meant to be referenced by a list pointer or some other pointer.