Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ can't initialize a pointer in a pair to NULL

I'm compiling with g++ 4.4.7 (and can't go any higher currently), and using the -std=gnu++0x compiler switch, which should allow the syntax of the third line.

typedef std::vector<CI_RecordInfo_Pair>   CI_RecordInfo_Vector;
typedef std::vector<std::pair<std::string, CI_RecordInfo_Vector*> > MgrBlks;
MgrBlks mgr_n_blks { {"T2M_NAME", NULL} };  // <--- line 59

However, the compiler complains as follows:

/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_pair.h: In constructor 'std::pair<_T1, _T2>::pair(_U1&&, _U2&&) [with _U1 = const char (&)[9], _U2 = long int, _T1 = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _T2 = CI_RecordInfo_Vector*]':
tom.cpp:59:   instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/bits/stl_pair.h:90: error: invalid conversion from 'long int' to 'CI_RecordInfo_Vector*'

I assume the "long int" is the NULL, and that for some reason I'm unable to convert it to a pointer. Yet elsewhere in a map of structs, I was able to compile something like

foo["X"] = { NULL, "bar", 12 }; // first element is a pointer

What is the difference?

like image 460
Chap Avatar asked Aug 13 '13 19:08

Chap


People also ask

Can you initialize a pointer to null in C?

A pointer can also be initialized to null using any integer constant expression that evaluates to 0, for example char *a=0; . Such a pointer is a null pointer.

Can you set a pointer to null?

We can directly assign the pointer variable to 0 to make it null pointer.

What happens when we set pointer to null?

What happens if you set the pointer to NULL before freeing the memory? If you try to free a null pointer, nothing will happen. If there are other pointers to the same memory, they can continue to be used to reference and eventually free the memory.


1 Answers

The compiler is correct to reject this line:

MgrBlks mgr_n_blks { {"T2M_NAME", NULL} };

In C++11 std::pair has a template constructor that takes any argument types, then converts them to the members:

template<typename X, typename Y>
  pair(X&& x, Y&& y)
  : first(std::forward<X>(x)), second(std::forward<Y>(y))
  { }

NULL must be defined as 0 or 0L or something similar, so template argument deduction deduces the constructor's template arguments as const char* and (with GCC) long. The first argument type is convertible to std::string but long is not convertible to CI_RecordInfo_Vector*, so the constructor cannot be called.

For the other case with a map of structs there is no argument deduction, the RHS of the assignment must be convertible to the struct type, and in that case NULL is used to directly initialize the struct's first member, rather than first being deduced as a long and initializing a long, which cannot be converted to a pointer.

Do not use NULL in C++11, nullptr was invented to avoid exactly these problems, you should use it.

A possible workaround would be to cast the argument to the right type:

MgrBlks mgr_n_blks { {"T2M_NAME", (CI_RecordInfo_Vector*)NULL} };

but it's simpler and clearer just to use nullptr.

like image 99
Jonathan Wakely Avatar answered Oct 13 '22 04:10

Jonathan Wakely