How should I properly initialize a C struct from C++? - c++

I have the following code in a C++ file:
#include <sys/socket.h>
// ...
void someFunc() {
struct msghdr msg = {0}; // <<< Uninitialized member here
}
When I compile with g++ using -Wall -Wextra, I get warnings:
error: missing initializer for member 'msghdr::msg_namelen'
...same for several other fields
My problem is this: I can't explicitly initialize all the fields, because I don't know what fields will exist (cross-platform) in a struct msghdr. The struct doesn't have a default constructor, since it's a C struct. I was under the impression that the = {0} form led to zero-initialization of all fields (which would be fine for me), but the g++ error message suggests not.
What are my options here?

Do this:
void someFunc()
{
msghdr msg = {}; // <<< All members zero-initialized
}
The g++ -Wextra warning level is IMHO not very useful.
The code that you have is also formally OK for a "C struct", in standardeese known as POD (plain old data structure). But your code explicitly initializes the first member with 0. That won't necessarily work for an aggregate that isn't POD, e.g., with a std::string as the first member, while the pure {} will work also for that.
In passing, often a POD like the one you're dealing with has a byte count as the first member, and then you can do like …
void foo()
{
SomePODStruct o = {sizeof(o)}; // The other members zero-initialized.
}
Perhaps add a STATIC_ASSERT that the byte count member is first (at offset 0).

This should work:
memset(&msg, 0, sizeof(msg));

The specific warning flag that causes this is -Wmissing-field-initializers, which is turned on as part of -Wextra. The simplest way to avoid this (bogus) warning is therefore to use -Wno-missing-field-initializers.

If you can't live with the warning and/or don't want to disable the warning, then I think it will have to be explicit initialisation via e.g. memset:
memset(&msg, 0, sizeof(msg));

Related

The proper way to initialize array of char with constant string

I use a struct to transfer data over TCP-IP and I have to stick with certain packet size, so I use char array of fixed size for text data. Due to the fact that I can't initialize it otherwise, I forced to copy string to that array in constructor using simple function (based on strcpy). The problem is: analyzer (clang-tidy Ubuntu LLVM 14.0.0) tells me
warning: constructor does not initialize these fields: receiver [cppcoreguidelines-pro-type-member-init]
but in fact that is not true. Tell me, please, how do I change my code to suppress those warnings messages? I understand, that I can initialize those arrays with zeros using {} and than fill them with the needed data, but it looks like double work..
inline void copyName(char *dst, const char *src) {
strncpy(dst, src, MAX_NAME_LENGTH);
}
struct Header {
const MessageType type;
char receiver[MAX_NAME_LENGTH];
static uint32_t messageId;
Header();
Header(MessageType type, const char* receiver);
};
Header::Header(const MessageType type, const char *receiverName)
: type(type) // the warning is here
{
copyName(receiver, receiverName);
Header::messageId++;
}
P.S> Found some workaround (which, of course, not the answer to the actual question): there is the option IgnoreArrays for that warning which, when set to true, suppresses those warnings
The warning is a false positive. The clang-tidy docs for the warning you got say:
The check takes assignment of fields in the constructor body into account but generates false positives for fields initialized in methods invoked in the constructor body.
https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.html
Seems like a poor check to me, but if you want to keep it enabled you might be able to suppress this one instance of it using the magic // NOLINT comment...somewhere?

c++ static unorderd_map used in static method is not initialized

I have some code where a static method is called, and the static std::unordered_map within the same file is not initialized. I understand the static initialization between two compile units is "undefined" and there are many SO questions on the topic; however, when I use an std::vector the issue does not occur. Also, the code can execute, but I am confused as to why these specific compile orders do not work. SO, my questions are:
There is another SO question (which I've been unable to find!) about static initialization and dynamic initialization of static variables. Is this error due to std::undored_map actually being a dynamic initialization?
is there a way to get this code to initialize the std::unordered_map as I expected? I'm actually trying to create a static library .lib or .a. When I link the static library, it generally needs to come last, and so the error occurs.
are there any workarounds for this? One option I've thought of is to create both an std::vector and an std::unordered_map. Use the std::vector while the std::unordered_map is uninitialized (via bool _map_is_initialized). Change the initialization of the std::unordered_map to be explicitly dynamic by calling a function which iterates over the values in the std::vector to produce the std::unordered_map.
Linux
g++ -std=c++1y -g -c thing.cpp
g++ -std=c++1y -g -c main.cpp
g++ -g main.o thing.o -o main
./main
This results in a Floating point exception (core dumped) error. Through gdb, I was able to figure out that hashtable_policy.h trys __num % __den; where __den==0. Also using gdb, it appears as though Thing::Things is uninitialized.
(gdb) break thing.cpp:12
(gdb) run
(gdb) print Thing::Things
No symbol "Things" in specified context.
(gdb) print thing
$1 = (Thing *) 0x618c20
Windows
cl /EHsc /Zi /c main.cpp
cl /EHsc /Zi /c thing.cpp
link /debug main.obj thing.obj
main
In my actual code, this resulted in a very clear segmentation fault; however, this example just opens a popup that says the application failed. ... I have not done better diagnostics.
Code
thing.cpp
#include<iostream>
#include "thing.hpp"
std::vector<Thing*> Before; // EDIT: added
std::unordered_map<std::string, Thing*> Thing::Things;
std::vector<Thing*> After; // EDIT: added
Thing::Thing(std::string name) : name(name) {
}
bool Thing::Register(Thing *thing) {
std::cout << "no worries, vectors initialized..." << std::endl;
Thing::Before.push_back(thing); // EDIT: added
Thing::After.push_back(thing); // EDIT: added
std::cout << "added to vectors, about to fail..." << std::endl;
Thing::Things[thing->name] = thing;
return true;
}
thing.hpp
#pragma once
#include <string>
#include <unordered_map>
class Thing {
public:
static std::vector<Thing*> Before; // EDIT: added
static std::unordered_map<std::string, Thing*> Things;
static std::vector<Thing*> After; // EDIT: added
static bool Register(Thing* thing);
std::string name;
Thing(std::string name);
};
#define ADD_THING(thing_name) \
static bool thing_name## _is_defined = Thing::Register(new Thing( #thing_name ));
main.cpp
#include "thing.hpp"
#include <iostream>
ADD_THING(obligatory);
ADD_THING(foo);
ADD_THING(bar);
int main(int argc, char* argv[]) {
std::cout << "before loop" << std::endl;
for (auto thing : Thing::Things) {
std::cout << "thing.name: " << thing.first << std::endl;
}
return 0;
}
EDIT
If the order within a given compile unit is guaranteed, why do static std::vector<Thing*> Thing::Before and static std::vector<Thing*> Thing::After get initialized, but static std::unordered_map<std::string, Thing*> Thing::Things does not?
As noted in the comments, static initialization order is not defined. Who knows the difference between vector and map. Maybe your compiler initializes classes with even number of characters in their name first.
If you're running c++11 or greater, static initialization of function local items is guaranteed to be thread safe. They will be initialized the first time control passes through the declaration statement.
// Header
class Thing {
public:
static std::unordered_map<std::string, Thing*>& Things();
static bool Register(Thing* thing);
// CPP
std::unordered_map<std::string, Thing*>& Thing::Things()
{
static std::unordered_map<std::string, Thing*> things;
return things;
}
This will initialize the first time you ask for the Things, and avoids all the potential randomness of static initialization.
Static initialization is tricky. As this answer states, the standard provides some guarantees as to the order of initialization within a single "translation unit" (normally a .cpp source file), but none whatsoever concerning what order initializations in different translation units will follow.
When you added the Before and After vectors to the code, you observed that unlike the calls to ordered_map::operator[], the calls to vector::push_back() did not crash the process and concluded that the objects were being initialized out of order within a single translation unit, contrary to the standard's guarantees. There is a hidden assumption there, namely that since push_back() did not cause a crash, the vector must therefore have been initialized. This turns out not to be the case: that method call on an uninitialized object is almost certainly corrupting memory somewhere, but won't necessarily cause a crash. A better way of checking whether or not the constructor is being called would be to run the code in a debugger, and set breakpoints on the lines which contain the objects' definitions, for instance std::vector<Thing*> Before in thing.cpp. This will show that initialization will occur as predicted in the standard.
The best option for avoiding the "fiasco", as described here, is "construct on first use". In the case of your example code, this would involve changing any direct use of Thing::Things, such as this line:
Thing::Things[thing->name] = thing;
To a method, say Thing::GetThings(), which initializes the object and returns a reference to it. lcs' answer provides an example of this, but beware: although it solves the static initialization problem, using a scoped static object may introduce an even more pernicious problem: crashes on program exit due to static deinitialization order. For that reason, allocating the object with the new keyword is preferred:
std::unordered_map<std::string, Thing*>& Thing::GetThings()
{
static std::unordered_map<std::string, Thing*>* pThings =
new std::unordered_map<std::string, Thing*>();
return *pThings;
}
That instance will of course never be delete'd, which feels an awful lot like a memory leak. But even if it weren't a pointer, de-initialization would only occur at program shutdown. So, unless the object's destructor performs some important function like flushing a file's contents to disk, the only difference that matters is the fact that using a pointer avoids the possibility of a crash on exit.

How to use C++ enums without getting a compiler warning

I need to communicate that one and the same enum is passed to several calls. So I am doing this:
MiddleEarth::Creatures ally = MiddleEarth::Creatures::Elf;
myEnergy->Transfer(ally, 10);
myLives->Transfer(ally, 1);
Both Transfer methods are declared as follows:
Energy::Transfer(const Creatures& transferTo, (snip)
However, I am getting the following warning on the declaration of the variable named ally:
warning C4482: nonstandard extension used: enum 'MiddleEarth::Creatures' used in qualified name
What am I doing wrong? How do I rewrite my code so that it does not generate a compiler warning?
From the MSDN page on the warning;
When you refer to an enum inside a type, you do not need to specify the name of the enum.
int i = S::E::a; // C4482
int j = S::a; // OK
so in your case;
MiddleEarth::Creatures::Elf
should be
MiddleEarth::Elf
You probably want:
MiddleEarth::Creatures ally = MiddleEarth::Elf;

better method for initializing array

Looks a newbie question, but this function is called many times, to be honest thousands of time per-second, so an optimization is CRUCIAL in here. What would be the best method?
struct CHOLDELEM
{
DWORD dwColor[3], dwItemId[3];
int nPos[3], nLength[3];
CItemElem* pItem[3];
CHOLDELEM()
{
for( int i=0; i<=3; i++ )
{
dwColor[i] = dwItemId[i] = 0;
nPos[i] = nLength[i] = 0;
pItem[i] = NULL;
}
}
};
or with memsets?
memset( dwColor, 0, sizeof( dwColor ) );
or another method.
As long as you are interested in zero initialization only, you can simply do
CHOLDELEM() : dwColor(), dwItemId(), nPos(), nLength(), pItem()
{}
(no C++11 necessary).
However, you might want to take a look at the code your compiler generates for it. If it is not optimal somehow, then a better idea might be to keep your struct a POD (no constructor) and initialize it "from outside" when you declare objects of that type
CHOLDELEM c = {};
If your compiler can handle C++11 initializers, then you can set the array values in the constructor initializer list:
CHOLDELEM() :
dwColor{0}, dwItemId{0}, nPos{0}, nLength{0}, pItem{nullptr}
{ }
Then the compiler will generate (pretty optimal) code to handle that.
I would probably use the memset approach, but I would definitely want to make sure that it doesn't break when more complex data members are added to CHOLDELEM:
#include <type_traits>
// ...
CHOLDELEM()
{
static_assert(std::is_trivially_copyable<CHOLDELEM>::value,
"It is no longer safe to use memset!");
memset(this, 0, sizeof *this);
}
By the way, CHOLDELEM is a terrible name. Why don't you rename it to ElementHolder or something?

Union initialisation in a struct

I've been browsing stackoverflow concerning the problem of initialising a union in a struct but I didn't manage to get it right.
Here is my struct
typedef struct dc_netif_filter {
unsigned char filter_type;
union {
uint32_t itf_nb;
char * buf;
} value;
} dc_netif_filter_t;
In my code, i have tried to use :
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME,{{0, "tun"}}};
which gives error: braces around scalar initializer for type ‘uint32_t’
and
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME,{0, "tun"}};
which gives error: too many initializers for ‘dc_netif_filter::< anonymous union>’
How do i declare such a dc_netif_filter_t ?
I'm using g++ on ubuntu. Note that the dc_netif_filter_t isn't a struct that I can modify as it comes from a third party project.
**EDIT : as I've been explained, i can only initialise one field. The problem is that with
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME,"tun0"};
I get a conversion error : invalid conversion from ‘const char*’ to ‘uint32_t
Thanks
As the compiler says, too many initializers for ‘dc_netif_filter::< anonymous union>’.
Initialize only one field, not both.
Use the name of the field to initialize it properly:
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME, { buf: "tun0" }};
It looks like you are trying to initialize your structure to indicate that the buf member is to be used, and that the value of that buf should be "tun". Since C++ before C++11 lacks designated initializers, you cannot do it with an initializer: only the first field of the union can be initialized, so you need to do your assignment in code:
static get_dc_netif_filter_t() {
static c_netif_filter_t netif = {DC_NETIF_SELECT_NAME, {0}};
if (netif.value.itf_nb == 0) {
netif.value.buf = "tun";
}
return netif;
}
C++11 lets you do it like this:
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME, { .buf = "tun"}};
This works under g++ 4.7.0:
dc_netif_filter_t netif = {DC_NETIF_SELECT_NAME, {.buf="tun"}};
Although designated initializers are supposed to be C only, not C++! Maybe it's a GNU extension?
I guess the best (most compatible) way is to assign the members after initialization:
dc_netif_filter_t netif;
netif.itf_nb = DC_NETIF_SELECT_NAME;
netif.value.buf = "TUN";