Maybe I didn't know how to search, but it's fact that I couldn't find anyone talking about this.
I have struct that has a non-type argument that depends on a type argument.
template<
typename SpecType,
SpecType NonType >
struct Struct
//...
When SpecType is a reference to a pointer (const char *&, for example) NonType behaves as if it is the address of the actual specialized argument, and not a reference.
More surprising is that if I explicitly cast NonType to SpecType, everything works as expected!
IBM says something about conversion to pointer of arrays and functions, but I don't understand it as related to my doubt.
When I create structs that have no embedded template types (S1 and S2) the same thing does ot happen.
Of course I can change it to:
template<
typename SpecType,
SpecType &NonType >
but it won't explain what I see.
Can anyone please give a deep (or dumb, if it is my stupidness) explanation?
The following example is a bit extense, but looking at its output I think my problem will be more clear:
#include <iostream>
#include <typeinfo>
using namespace std;
void f1( const char **p )
{
cout << "---------------------------------------------" << endl;
cout << "f1( const char **p ): p = \"" << p << "\"" << endl;
}
void f1( const char *p )
{
cout << "---------------------------------------------" << endl;
cout << "f1( const char *p ): p = \"" << p << "\"" << endl;
}
void f1( const int **p )
{
cout << "---------------------------------------------" << endl;
cout << "f1( const int **p ): p = \"" << p << "\"" << endl;
}
void f1( const int *p )
{
cout << "---------------------------------------------" << endl;
cout << "f1( const int *p ): p = \"" << p << "\"" << endl;
}
template<
typename SpecType,
SpecType NonType >
struct Struct
{
void f( )
{
cout << "---------------------------------------------" << endl;
cout << "SpecType is " << typeid( SpecType ).name( ) << endl;
cout << "NonType is " << typeid( NonType ).name( ) << endl;
cout << "NonType = \"" << NonType << "\"" << endl;
cout << "( SpecType )NonType = \"" << ( SpecType )NonType << "\"" << endl;
cout << "*NonType = \"" << *NonType << "\"" << endl;
cout << "*NonType[ 0 ] = \"" << **NonType << "\"" << endl;
f1( NonType );
}
};
template< const char *&P >
struct S1
{
void f( )
{
cout << "---------------------------------------------" << endl;
cout << "&P = \"" << &P << "\"" << endl;
cout << "P = \"" << P << "\"" << endl;
cout << "*P = \"" << *P << "\"" << endl;
f1( P );
}
};
template< const char **P >
struct S2
{
void f( )
{
cout << "---------------------------------------------" << endl;
cout << "P = \"" << P << "\"" << endl;
cout << "*P = \"" << *P << "\"" << endl;
cout << "*P[ 0 ] = \"" << **P << "\"" << endl;
f1( P );
}
};
const char * const_pname = "name";
const int pint[] = { 42, 51 };
const int *const_pint = pint;
int main( )
{
cout << "=============================================" << endl;
cout << "const_pname = " << const_pname << endl;
cout << "#const_pname = 0x" << hex << ( unsigned long )const_pname << dec << endl;
cout << "&const_pname = 0x" << hex << ( unsigned long )&const_pname << dec << endl;
cout << "=============================================" << endl;
cout << "Struct< const char *&, const_pname > constpTtname" << endl;
Struct< const char *&, const_pname > constpTtname;
constpTtname.f( );
cout << "=============================================" << endl;
cout << "Struct< const int *&, const_pint > constpTtint" << endl;
Struct< const int *&, const_pint > constpTtint;
constpTtint.f( );
cout << "=============================================" << endl;
cout << "S1< const_pname > s1" << endl;
S1< const_pname > s1;
s1.f( );
cout << "=============================================" << endl;
cout << "S2< &const_pname > s2" << endl;
S2< &const_pname > s2;
s2.f( );
return 0;
}
The output is:
$ ./nontype_mutant
=============================================
const_pname = name
#const_pname = x401624
&const_pname = 0x601e18
=============================================
Struct< const char *&, const_pname > constpTtname
---------------------------------------------
SpecType is PKc
NonType is PKc
NonType = "$#"
( SpecType )NonType = "name"
*NonType = "name"
*NonType[ 0 ] = "n"
---------------------------------------------
f1( const char *p ): p = "$#"
=============================================
Struct< const int *&, const_pint > constpTtint
---------------------------------------------
SpecType is PKi
NonType is PKi
NonType = "0x601e20"
( SpecType )NonType = "0x4017a8"
*NonType = "0x4017a8"
*NonType[ 0 ] = "42"
---------------------------------------------
f1( const int *p ): p = "0x601e20"
=============================================
S1< const_pname > s1
---------------------------------------------
&P = "0x601e18"
P = "name"
*P = "n"
---------------------------------------------
f1( const char *p ): p = "name"
=============================================
S2< &const_pname > s2
---------------------------------------------
P = "0x601e18"
*P = "name"
*P[ 0 ] = "n"
---------------------------------------------
f1( const char **p ): p = "0x601e18"
I've tried to compile your code using three compilers and two of them have very similar behavior giving the following message (approximately):
test.cpp:44:41: error: indirection requires pointer operand ('int' invalid)
cout << "*NonType[ 0 ] = \"" << **NonType << "\"" << endl;
^~~~~~~~~
test.cpp:93:18: note: in instantiation of member function 'Struct<const char *&, const_pname>::f' requested here
constpTtname.f( );
^
test.cpp:44:41: error: indirection requires pointer operand ('int' invalid)
cout << "*NonType[ 0 ] = \"" << **NonType << "\"" << endl;
^~~~~~~~~
test.cpp:98:17: note: in instantiation of member function 'Struct<const int *&, const_pint>::f' requested here
constpTtint.f( );
^
2 errors generated.
The error message seems correct and self evident to me. This was the result of using clang. Comeau's EDG based compiler was the other one to give a message very similar to this.
g++ compiled it (I believe incorrectly) and gave an output similar to that you report.
Related
I'm working with C++ pointers and I've encountered something curious.
If I reset a pointer to itself using "b = (int*)&b;", I expected the deferenced output to be the memory address of itself -- since it was pointing to itself.
So I thought *b would be "0x7ffea00819b0", but it's some strange numeric value.
But this isn't the case. The alternate value I get is confusing.
Here is my output:
Value of a = 10
Address of a = 0x7ffea00819ac
Value of b = 0x7ffea00819b0
Address of b = 0x7ffea00819b0
Dereference of b = -1610081872
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
int a = 10;
int *b = &a;
b = (int*)&b;
cout << "Value of a = " << a << endl;
cout << "Address of a = " << &a << endl << endl;
cout << "Value of b = " << b << endl;
cout << "Address of b = " << &b << endl;
cout << "Dereference of b = " << *b << endl;
}
Changing the type to unsigned long int fixed the issue.
Thank you all!
#include <iostream>
#include <type_traits>
using namespace std;
int main(int argc, char** argv)
{
unsigned long int a = 10;
unsigned long int *b = &a;
b = (unsigned long int*)&b;
cout << "Value of a = " << a << endl;
cout << "Address of a = " << &a << endl << endl;
cout << sizeof b << endl;
cout << sizeof *b << endl;
//static_assert(sizeof b == sizeof *b);
cout << "Value of b = " << b << endl;
cout << "Address of b = " << &b << endl;
cout << "Dereference of b = " << hex << "0x" << *b << endl;
}
#include <iostream>
using namespace std;
void swap(int& a, int& b)
{
cout << "address of a: " << &a << " value of a: " << a << endl;
cout << "address of b: " << &b << " value of b: " << b << endl;
int tmp{move(a)};
cout << "address of tmp: " << &tmp << " value of tmp: " << tmp << endl;
a = move(b);
b = move(tmp);
cout << "address of a: " << &a << " value of a: " << a << endl;
cout << "address of b: " << &b << " value of b: " << b << endl;
}
void swap_no_move(int& a, int& b)
{
cout << "address of a: " << &a << " value of a: " << a << endl;
cout << "address of b: " << &b << " value of b: " << b << endl;
int tmp{ a };
cout << "address of tmp: " << &tmp << " value of tmp: " << tmp << endl;
a = b;
b = tmp;
cout << "address of a: " << &a << " value of a: " << a << endl;
cout << "address of b: " << &b << " value of b: " << b << endl;
}
int main() {
int a = 10;
int b = 5;
swap(a, b);
cout << endl;
int c = 10;
int d = 5;
swap_no_move(c, d);
cin.get();
return 0;
}
I have two swap functions: swap and swap_no_move. According to what I read from the book, there should be no "copy" in function swap which means the address of tmp should be the same for tmp and an in function swap. However, the output I got shows there is no difference between these two functions, did I do something wrong?
The definition
int tmp{move(a)};
doesn't move the reference or the variable a itself. It creates a brand new variable tmp which the compiler allocates space for. Then the value of a is moved into tmp.
And since moving int values can't really be done, it's exactly the same as
int tmp = a;
The following static initializer list M fails but N suceeds, it seems I cannot figure out how to do the unordered_map initialization when a union of 3 const char * pointers is added to the init-list. I tried the . notation to access the fields of the union and the union itself to no avail.
#include <iostream>
#include <unordered_map>
#include <iterator>
struct C {
int j;
int i;
};
struct D {
int j;
char c;
};
struct E {
const char *a;
const char *b;
const char *c;
}e;
struct A {
const char *s;
union {
C c;
D d;
E e;
} u;
};
std::unordered_map<unsigned int, A> m ({
{1, {"tom",53,'o'}},
{2, {"ming",40,41}},
{3, {"peter","a","b","c"}} });
std::unordered_map<unsigned int, A> n ({
{1, {"tom",53,'o'}},
{2, {"ming",40,41}} });,
int main(void) {
for ( const auto& i : m) {
const auto& j = i.second;
if (i.first == 1)
std::cout << "key: " << i.first << " value: " << j.u.d.j << ":" << j.s << ":" << j.u.d.c << std::endl;
else if (i.first == 2)
std::cout << "key: " << i.first << " value: " << j.u.c.j << ":" << j.s << ":" << j.u.c.i << std::endl;
else if (i.first == 3)
std::cout << "key: " << i.first << " value: " << j.u.e.a << ":" << j.s << ":" << j.u.e.c << std::endl;
}
for ( const auto& i : n) {
const auto& j = i.second;
if (i.first == 1)
std::cout << "key: " << i.first << " value: " << j.u.d.j << ":" << j.s << ":" << j.u.d.c << std::endl;
else if (i.first == 2)
std::cout << "key: " << i.first << " value: " << j.u.c.j << ":" << j.s << ":" << j.u.c.i << std::endl;
}
return 0;
}
Error:
map.cpp:41:32: error: no matching function for call to ‘std::unordered_map::unordered_map()’
int value = 3;
int *pValue1 = &value;
int *pValue2(pValue1);
cout << (*pValue1) << " " << (*pValue2);
In the above code if you have noticed I have written
int *pValue2(pValue1);
instead of
int *pValue2 = new int;
pValue2 = pValue1;
Still it is working and giving proper result.
Can any one explain to me which of the default function or constructor is getting called in this case?
int *pValue2(pValue1);
is equivalent to
int* pValue2 = pValue1;
Just assign to pValue2 pValue1 (assign to pValue2 address of variable value).
The difference should be apparent if you print the pointers themselves (the addresses) in addition to the values which they reference:
#include <iostream>
using namespace std;
int main() {
int value = 3;
int *pValue1 = &value;
int *pValue2(pValue1);
int *pValue3 = new int;
cout << pValue1 << " " << pValue2 << " " << pValue3 << endl;
cout << *pValue1 << " " << *pValue2 << " " << *pValue3 << endl;
pValue3 = pValue1;
cout << pValue1 << " " << pValue2 << " " << pValue3 << endl;
cout << *pValue1 << " " << *pValue2 << " " << *pValue3 << endl;
return 0;
}
You will also see that after new int, the memory pointed to by the pointer contains uninitialized data.
This question already has answers here:
Passing a char pointer array to a function
(2 answers)
Closed 8 years ago.
Note 1: I am not looking for different solutions to the problem at hand. I'm curious about what actually is happening here.
Note 2: I'm doing this in c++ context, but am assuming that this also applies to C, hence the C tag. (apart from the representation of a null pointer)
This is about c-strings and access to original from a function. I'll use argv and argc to illustrate that the array should be nullptr terminated. I declare them like this:
int argc = 1;
char **argv = (char**) malloc( (argc + 1) * sizeof(char*) );
argv[0] = (char*)"argument 0";
argv[1] = nullptr;
If I declare a function like this: func1(int &f_argc, char **f_argv) I can access all elements inside the function scope, including f_argv[f_argc], which is nullptr, but I cannot modify the original argv to point to a different address as f_argv in the function is a value passed copy of the original pointer. It has a different address in memory.
If I declare the function like this instead: func2(int &f_argc, char ***f_argv), I can access the original argv through *f_argv in the function, but the last element (which should be nullptr) is cut off. This means that if I try to check for the terminating nullptr inside the function, I try to access an element outside the range of the array, resulting in a core dump at runtime.
Q1: Why is f_argv cut off when reaching the nullptr in func2, but not in func1?
Q2: Is there a way to get write access to the original argv from within the function, without removing the terminator?
Edit: (added code to show what I mean)
#include <iostream>
#include <cstring>
void func1(int &f_argc, char **f_argv) {
using std::cout;
using std::endl;
cout << " In function:" << endl;
cout << " argv passed as **f_argv" << endl;
cout << " f_argv = " << f_argv << " , &f_argv = " << &f_argv << endl;
for (int pos = 0; pos < f_argc; pos++) {
if (f_argv[pos] != nullptr) {
cout << " f_argv[" << pos << "] = \"" << f_argv[pos] << "\"" << endl;
} else {
cout << " f_argv is prematurely terminated" << endl;
}
}
if (f_argv[f_argc] == nullptr) {
cout << " f_argv is correctly terminated" << endl;
} else {
cout << " f_argv[" << f_argc << "] = \"" << f_argv[f_argc] << "\"" << endl;
cout << " f_argv is not terminated" << endl;
}
// Intention is to copy argv here, add elements, terminate it with
// nullptr and change original argv to point to copy. This wouldn't
// work in this function, as &f_argv != &argv.
return;
}
void func2(int &f_argc, char ***f_argv) {
using std::cout;
using std::endl;
cout << " In function:" << endl;
cout << " array passed as ***f_argv" << endl;
cout << " f_argc = " << f_argc
<< " , &f_argc = " << &f_argc << endl;
cout << " *f_argv = " << *f_argv
<< " , f_argv = " << f_argv << endl;
for (int pos = 0; pos < f_argc; pos++) {
cout << " about to check: "
<< "if (*f_argv[" << pos << "] != nullptr)" << endl;
if (*f_argv[pos] != nullptr) {
cout << " *f_argv[" << pos << "] = \""
<< *f_argv[pos] << "\"" << endl;
} else {
cout << " *f_argv is prematurely terminated" << endl;
}
}
if (*f_argv[f_argc] == nullptr) {
cout << " *f_argv is correctly terminated" << endl;
} else {
cout << " *f_argv[" << f_argc << "] = \""
<< *f_argv[f_argc] << "\"" << endl;
cout << " *f_argv is not terminated" << endl;
}
// Intention is to copy argv here, add elements, terminate it with
// nullptr and change original argv to point to copy.
return;
}
// --------------------------------------------
int main() {
using std::cout;
using std::endl;
int argc=1;
char **argv = (char**) malloc( (argc + 1) * sizeof(char*) );
argv[0] = (char*)"argument 0";
argv[1] = nullptr;
cout << "Before function call" << endl;
cout << "argv = " << argv << " , &argv = " << &argv << endl;
for (int i = 0; i < argc; i++) {
if (argv[i] != nullptr) {
cout << "argv[" << i << "] = \"" << argv[i] << "\"" << endl;
} else {
cout << "argv is prematurely terminated" << endl;
}
}
if (argv[argc] == nullptr) {
cout << "argv is correctly terminated" << endl;
} else {
cout << "argv[" << argc << "] = \"" << argv[argc] << "\"" << endl;
cout << "argv is not terminated" << endl;
}
// run one of these
//func1(argc, argv);
func2(argc, &argv);
free(argv);
return 0;
}
If running func2, running the program results in a core dump at this line:
if (*f_argv[f_argc] == nullptr) {
The subscript operator has higher precedence than the dereference operator. *f_argv[f_argc] is *(f_argv[f_argc]). What you want is (*f_argv)[f_argc].
Since you are using C++, you should consider taking f_argv by reference - void f(int &f_argc, char **& f_argv);.