Could someone explain to me why the offsetof function does not work on std::vectors as shown below:
#include <windows.h>
#include <iostream>
#include <vector>
using namespace std;
struct FooStruct {
double x;
double y[10];
std::vector<double> z;
};
int main() {
cout << offsetof(FooStruct, x) << endl;
cout << offsetof(FooStruct, y[2]) << endl;
cout << offsetof(FooStruct, z[2]) << endl;
system("Pause");
}
Calling offsetof(FooStruct, z[2]) produces the following compiling error:
cannot apply 'offsetof' when 'operator[]' is overloaded
offsetof(FooStruct, z[2]) makes no sense. The elements of z are not contained within a FooStruct, they're accessed via the std::vector, which has at its core a pointer to some other allocation on the heap within which z[2] can be found.
In any case, the error (which seems confusing I understand) is probably popping up because std::vector overloads operator[], not because your class FooStruct overloads operator[] (which, assuming we see the whole definition, it doesn't).
If you want to find the offset of z[2] in relation to z[0], you could just compute the difference between &z[0] and &z[2] like this: std::cout << (&z[2] - &z[0]) << '\n';
Because offsetof isn't a function but a macro, and only works on POD types, or standard layout class in C++11. It's only there for backward compatibility with C.
The reason the compiler refuses to allow you to use the subscription operator, all issues aside, is because the macro is evaluated at compile time, but the overloaded operator might do some work at runtime to calculate the result.
Related
I see some people tend to initialize a vector with an empty {}, and I wonder whether it is different from directly initialize with the default constructor?
for example:
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int> vec;
vector<int> vec2 {};
cout << sizeof(vec) << " " << sizeof(vec2) << endl; // 24 24
cout << vec.size() << " " << vec2.size() << endl; // 0 0
}
and I check its assembly code, and it shows that initializing a vector with an empty {} generate more code(https://godbolt.org/z/2BAWU_).
Assembly code screen shot here
I am quite new to C++ language, and I would be grateful if someone could help me out.
Using braces is value initialization. Not using them is default initialization. As somebody alluded to in the comments, they should generate the exact same code when optimizations are turned on for vector. There's a notable difference with built-in types like pointers and int; there default initialization does nothing, while value initialization sets them to nullptr and zero, respectively.
C++11 allows an anonymous union to be defined in a function, and its members can be accessed as variables of the function. If I examine the pointers to the different members, they are the same, but the == operator says they're unequal.
Such strange behavior is typically the result of undefined behavior, but I don't see anything undefined in my code (I made sure to that both members are of the same type).
The behavior is different if I use a named variable of an unnamed union type. In this case, the pointers compare equal.
This program demonstrates both cases:
#include <iostream>
using namespace std;
#ifdef NAMED
// Create a named object of a union type
#define NAME n
#define ADDR(mem) &(NAME.mem)
#else
// Create an anonymous union in main()
#define NAME
#define ADDR(mem) &mem
#endif
int main()
{
union {
int a;
int b;
} NAME;
cout << "&a = " << ADDR(a) << endl;
cout << "&b = " << ADDR(b) << endl;
cout << "(&a==&b) = " << (ADDR(a) == ADDR(b)) << endl;
return 0;
}
When compiled with -DNAMED it prints to identical pointers, and 1 (equal pointers). Without -DNAMED, it again prints identical pointers, but then 0 (unequal pointers).
Tested with g++ 5.4.0, Ubuntu 16.04, x86_64.
Your address checking is well defined (as YSC pointed out) and the standard guarantees that all members shall have the same address (cfr. [class.union]/3).
You must have stumbled upon a now fixed compiler bug.
The following code doesn't quite work.
#include <type_traits>
#include <string>
#include <iostream>
template<std::size_t Len, class... Types>
using dataType = typename std::aligned_union<Len,Types...>::type;
int main()
{
dataType<1,int,float,std::string,char,bool> x;
dataType<1,int,float,std::string,char,bool> y;
new (&x) std::string("chicken");
new (&y) std::string("boiled");
std::swap(x,y);
std::cout << *reinterpret_cast<std::string*>(&x) << " " << *reinterpret_cast<std::string*>(&y) << std::endl;
}
for example, it prints chicke boiled without the n. It also hasn't swapped x and y, else it would print boiled chicken.
This can't possibly work. The correct behavior of the swap would require knowing which type the union contains. This is not a discriminated union, so any operation that relies on knowing which type the union contains will fail unless specifically provided that information.
I'd love to hear how you imagine this could work, even conceivably. What magic do you think std::swap could possibly do?
Consider the following snippet:
#include <iostream>
using namespace std;
int a[10][2];
int b[10][2];
int main(){
//intended
cout << a[0][0] - b[0][0] << endl;
//left out dimension by mistake
cout << a[0] - b[0] << endl;
}
Obviously (or maybe not per comments) the second case is valid pointer arithmetic in both C and C++ but in the code base I am working with it is generally a semantic mistake; a dimension has usually been left out in a nested for loop. Is there any -W flag or static analysis tool that can detect this?
You could use std::array which will not allow that:
using d1=std::array<int, 2>;
using d2=std::array<d1, 10>;
d2 a;
d2 b;
std::cout << a[0][0] - b[0][0] << endl; // works as expected
std::cout << a[0] - b[0] << endl; // will not compile
Another option is to use a specialized multidimensional array library with appropriate operator error handling, such as boost::multi_array (http://www.boost.org/doc/libs/1_55_0/libs/multi_array/doc/user.html). This is usually a better idea then using nested containers or POD arrays.
If this is only concern for << operator as in example, overload of operator << for int* might help - you can overload operator to generate compile-time error.
What is the difference between these two declarations?
int myints[5];
array<int,5> myints;
If I use the first declarations and the function size(), there will be a error "Member reference base type 'int [5]' is not a structure or union".
But if I use the second declarations and the function size(), the program works.
Why would the first declarations does not work?
#include <iostream>
#include <iomanip>
#include <array>
using namespace std;
int main()
{
//int myints[5]; //illegal
array<int,5> myints; //legal
cout << "size of myints: " << myints.size() << endl; //Error if I use the first declarations
cout << "sizeof(myints): " << sizeof(myints) << endl;
}
As others have pointed out, std::array is an extension added
to C++11 (so you may not have it), which wraps a C style array,
in order to give it some (but not all) of an STL-like interface.
The goal was that it could be used everywhere a C style array
could; in particular, it accepts the same initialization syntax
as C style arrays, and if the initialization type allows static
initialization, its initialization can be static as well. (On
the other hand, the compiler cannot deduce its size from the
length of the initializer list, which it can for the older
C style arrays.)
With regards to size, any experienced programmer will have
a size function in their toolkit, along the same lines as
std::begin and std::end (which are C++11 extensions, and
which everyone had in their toolkit before C++11 standardized
them). Something like:
template <typename T>
size_t
size( T const& c )
{
return c.size();
}
template <typename T, size_t n>
size_t
size( T (&a)[n] )
{
return n;
}
(In modern C++, the second could even be constexpr.)
Given this, you write size( myInts ), regardless of whether it
is an std::array or a C style array.
array<int,5> myints uses an std::array, a template that overlays enhanced functionality on-top of a "basic" C/C++ array (which is what int myints[5] is). With a basic array, you are just reserving a chunk of storage space, and are responsible for keeping track of its size yourself (although you can use sizeof() to help with this).
With the std::array you get helper functions that can make the array safer and easier to use.
std::array is new in C++11. As you have found, it has a size function. This tells you how many items are in the array.
sizeof on the other hand tells you how much memory a variable is taking up i.e. its size in bytes.
array is a template class that has size() as it's member function while int[] is simple C array
By using int myints[5]; , you are declaring an array of 5 ints on the stack, which is the basic C array.
Instead, by using array<int,5> myints; you are declaring an object of type array, which is a container class defined by the STL (http://en.cppreference.com/w/cpp/container/array), which in turns implements the size()function to retrieve the container's size.
The STL containers are built on top of the "basic" C types to provide extra functionality and to make it easier to manage them.
int myints[5]; has no function size() but you can do
int size = sizeof(myints)/ sizeof(int);
to get the size of the array.
so basically you can do:
#include <iostream>
#include <iomanip>
#include <array>
using namespace std;
int main()
{
int myintsArr[5]; //legal
array<int,5> myints; //legal
cout << "size of myints: " << myints.size() << endl; //Error if I use the first declarations
cout << "sizeof(myintsArr): " << sizeof(myintsArr)/ sizeof(int) << endl;
}
and get the same result from both the arrays