C++ define and initialize array of struct instances: Undefined Variable? - c++11

Question if C++11 supports initializing an array, so not a stl container, with an initializer list of structs that contain again an C++ type like std::string. See code below.
Compiler I'm using does NOT complain:gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)
Code seems to run perfect.
Valgrind does not complain.
But the static analyzer tool we are evaluating does complain:
const MyStruct02 myArr02[] = {
{"Value 0", 0, -1, 41943040},
Uninitialized Variable
myArr02 was not initialized.
myArr02 was defined at Repro001_Unitialized_Variable.cpp:49.
The analyzer is referring to: http://cwe.mitre.org/data/definitions/457.html
Code:
#include <string>
#include <iostream>
struct MyStruct01
{
const char* description;
int val1;
int val2;
int val3;
};
struct MyStruct02
{
std::string description;
int val1;
int val2;
int val3;
};
int main(int argc, const char* argv[])
{
const MyStruct01 myArr01[] = {
{"Value 0", 0, -1, 41943040},
{"Value 1", 10, 5000000, 10485760},
{"Value 2", 20, 1000000, 409600 },
{"Value 3", 30, 500000, 204800 },
{"Value 4_0", 40, 200000, 102400 }
};
std::cout << myArr01[0].description << std::endl;
const MyStruct02 myArr02[] = {
{"Value 0", 0, -1, 41943040},
{"Value 1", 10, 5000000, 10485760},
{"Value 2", 20, 1000000, 409600 },
{"Value 3", 30, 500000, 204800 },
{"Value 4_0", 40, 200000, 102400 }
};
std::cout << myArr02[0].description << std::endl;
return 0;
}
After some puzzling I found out that replacing the std::string in the struct by a native "const char*" removes the Uninitialized Variable warning.
So my question: Is the static analyzer tool right or is it wrong???
Thanks for any help.
Henry

Related

How std::thread object copies argument?

question updated !
I got a std::string object, and std::thread supposed to copy it into it's internal storage, why the code below still doesn't work?(FIXED)
If I detach t(f, 5, std::string(buf)), there are no output at all ! (FIXED)
#include <thread>
#include <iostream>
#include <unistd.h>
using namespace std;
void f(int i, const std::string &str) {
printf("i = %d, str = %s\n", i, str.c_str());
}
void oops(int ival) {
char *buf = new char[32]{0};
snprintf(buf, 32, "%i", ival);
// maybe danling pointer, if it's a danling pointer, the content of buf is undefined
// in this program it happens to be 1999.
std::thread t(f, 3, buf);
t.detach();
delete [] buf;
}
void not_oops(int ival) {
char *buf = new char[32]{0};
snprintf(buf, 32, "%i", ival);
std::thread t(f, 5, std::string(buf));
t.detach();
delete [] buf;
}
int main() {
oops(1992); // This is buggy
not_oops(1999);
}
expected output:
i = 3, str = 1992
i = 5, str = 1999
actual output:
i = 3, str = 1999
i = 5, str = 1999
Your program finishes before it is complete, your function exits scope before thread is complete, killing it.
void oops(int ival) {
char *buf = new char[32]{0};
snprintf(buf, 32, "%i", ival);
std::thread t(f, 3, buf); // maybe danling pointer
t.detach(); // no more waiting for it
delete [] buf; // thread is not started yet (probably)
} // thread is destroyed , and std::string dies.
Only way to make it work without vast changes to code, is to allow threads to be managed outside. Also you have to ensure that a new std::string is created, or thread appears to use same storage for both.
void f(int i, const std::string &str) {
printf("i = %d, str = %s\n", i, str.c_str());
}
std::thread *t;
void oops(int ival) {
char *buf = new char[32]{0};
snprintf(buf, 32, "%i", ival);
t = new std::thread(f, 3, std::string(buf)); // maybe danling pointer
//t.detach();
delete [] buf;
}
void not_oops(int ival) {
char *buf = new char[32]{0};
snprintf(buf, 32, "%i", ival);
std::thread t(f, 5, std::string(buf)); // FIXME: why it won't work ?
t.join();
delete [] buf;
}
int main() {
oops(1992); // This is buggy
not_oops(1999);
t->join();
delete t;
}

How to pass a compile time array with var length to a constructor?

I have the following code:
struct MyArrayEntry
{
int type;
int id;
};
template<size_t arraySize>
struct MyArray
{
template<typename T, typename... Types>
MyArray(T t, Types... ts) : data{ { t, ts... } } {}
int dataSize = arraySize;
MyArrayEntry data[arraySize];
};
void Blah()
{
static MyArray<3> kTest
(
{ 1, 4 },
{ 2, 5 },
{ 3, 6 }
);
}
But this fails to build with:
error C2661: 'MyArray<3>::MyArray': no overloaded function takes 3
arguments
What am I doing wrong here?
With the imformation you provide, I would suggest using a std::initializer_list and an std::copy call:
template<size_t arraySize>
struct MyArray
{
const int dataSize = arraySize; // Could as well make it constant
MyArrayEntry data[arraySize];
MyArray(std::initializer_list<MyArrayEntry> elements)
{
std::copy(begin(elements), end(elements), std::begin(data));
}
};
Create as
MyArray<3> kTest({ { 1, 4 }, { 2, 5 }, { 3, 6 } });
Sure it's an extra pair of curly-brackets {}, but it will make your code simpler.

C++ calling function with unknown type of arguments?

I am trying to achieve the same as RapidCheck: call any Callable no matter its arguments.
Here is an example from RapidCheck:
#include <rapidcheck.h>
int main() {
rc::check("Addition is commutative.",
[](int a, int b) {
RC_ASSERT(a + b == b + a);
});
return 0;
}
Unlike RapidCheck, which uses random data to call the Callable, I
would like to use a source of data. In particular, I am casting a uint8_t array to whatever type I need. (See the example below.)
I am okay with using C++17 but would prefer C++11. I currently only have a C++17 example.
My example below works for an arbitrary number of arguments to a Callable but not for arbitrary types of argument. And certainly not for mixed types of arguments.
I am doing this, so that I can use the awesome API of RapidCheck with libFuzzer from LLVM. Similar to my previous approach here (Example).
What I have so far with some comments (online):
// Compiles with Clang(trunk)/GCC(7.2) using -std=c++17!
#include <cassert>
#include <functional>
#include <iostream>
#include <mutex>
#include <string>
#include <type_traits>
/** Provides access to a uint8_t array as specific types.
*
* Fulfills thus the LLVMFuzzerTestOneInput-interface, which uses
* (uint8_t *Data, size_t Size) as input.
*/
class RawQueue {
public:
RawQueue(uint8_t *Data, size_t Size)
: data_(Data), size_(Size / sizeof(uint8_t)), index_(0){};
/** Takes one element of type T from queue.
*
* Throws if empty.
*
* NOTE: Little endianess means that uint8_t {1, 0, 0, 0} == int {1}.
*/
template <typename T> T pop() {
assert(data_);
std::scoped_lock<std::mutex> lock(data_mutex_);
const size_t new_index = index_ + sizeof(T) / sizeof(uint8_t);
if (new_index > size_) {
std::runtime_error(
"Queue depleted!"); // TODO: Thou shall not use plain runtime_error!
}
const T val = *reinterpret_cast<const T *>(&(data_[index_]));
index_ = new_index;
return val;
}
private:
const uint8_t *data_; ///< Warning: Ownership resides outside of RawQueue.
std::mutex data_mutex_;
const size_t size_;
size_t index_;
};
template <> std::string RawQueue::pop<std::string>() {
return std::string("Left-out for brevity.");
};
template <typename T, typename F, typename... Args>
decltype(auto) call(RawQueue *Data, F &&f, Args &&... args) {
if constexpr (std::is_invocable<F, Args...>::value) {
return std::invoke(f, args...);
} else {
assert(Data);
// Is there a way to deduce T automatically and for each argument
// independently?
auto val = Data->pop<T>();
return call<T>(Data, f, val, args...);
}
}
int adder(int a, int b, int c) { return a + b + c; }
std::string greeter(const std::string &name) { return "Hello, " + name + "!"; }
int mixed_arguments(int i, float f, const std::string &s) { return 42; }
int main() {
constexpr size_t Size = 16;
uint8_t Data[Size] = {1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0};
RawQueue data(Data, Size);
auto res_int = call<int>(&data, adder);
std::cout << "Integer result: " << res_int << std::endl;
auto res = call<std::string>(&data, greeter);
std::cout << "String result: " << res << std::endl;
// Impossible with current approach:
// std::cout << "Mixed-types: " << call(&data, mixed_arguments) << std::endl;
return 0;
}
You could use variadic templates.
If you want to call, at runtime, an arbitrary function of arbitrary signature with arbitrary arguments, you should consider using libffi (a foreign function interface library which knows your ABI and calling conventions).
I found a solution using callable.hpp. Answers which do not rely on an external library are still welcome!
The relevant new addition is this:
constexpr size_t pos = sizeof...(args);
typedef typename callable_traits<F>::template argument_type<pos> T;
auto val = Data->pop<T>();
Complete Example:
#include <cassert>
#include <functional>
#include <iostream>
#include <mutex>
#include <string>
#include <type_traits>
#include "external/callable/callable.hpp"
class RawQueue {
public:
RawQueue(uint8_t *Data, size_t Size)
: data_(Data), size_(Size / sizeof(uint8_t)), index_(0){};
/** Takes one element of type T from queue.
*
* Throws if empty.
*
* NOTE: Little endianess means that uint8_t {1, 0, 0, 0} == int {1}.
*/
template <typename T> T pop() {
assert(data_);
std::scoped_lock<std::mutex> lock(data_mutex_);
const size_t new_index = index_ + sizeof(T) / sizeof(uint8_t);
if (new_index > size_) {
// TODO: Thou shall not use plain runtime_error!
std::runtime_error("Queue depleted!");
}
const T val = *reinterpret_cast<const T *>(&(data_[index_]));
index_ = new_index;
return val;
}
private:
const uint8_t *data_; ///< Warning: Ownership resides outside of RawQueue.
std::mutex data_mutex_;
const size_t size_;
size_t index_;
};
template <> std::string RawQueue::pop<std::string>() {
std::scoped_lock<std::mutex> lock(data_mutex_);
assert(data_);
assert(index_ < size_);
size_t string_length = data_[index_]; // Up-to 255 ought to be enough.
const size_t new_index =
index_ + string_length + 1; // +1 b/c first value is length of string.
if (new_index > size_) {
// TODO: Thou shall not use plain runtime_error!
std::runtime_error("Queue depleted!");
}
const std::string val(reinterpret_cast<const char *>(&(data_[index_ + 1])),
string_length);
index_ = new_index;
return val;
};
template <typename F, typename... Args>
decltype(auto) call(RawQueue *Data, F &&f, Args &&... args) {
if constexpr (std::is_invocable<F, Args...>::value) {
return std::invoke(f, args...);
} else {
assert(Data);
constexpr size_t n_already = sizeof...(args);
constexpr size_t n_needed = callable_traits<F>::argc;
static_assert(n_needed >= n_already, "Too many arguments!");
constexpr size_t pos = n_already;
typedef typename callable_traits<F>::template argument_type<pos> T;
auto val = Data->pop<T>();
return call(Data, f, args..., val);
}
}
int adder(int a, int b, int c) { return a + b + c; }
std::string greeter(std::string a) { return "hello " + a; };
void mixed(int i, float f, std::string s) {
std::cout << "Mixed: " << i << ", " << f << ", " << s << std::endl;
}
int main() {
constexpr size_t Size = 28;
// clang-format off
uint8_t Data[Size] = {
3, 'A', 'd', 'a',
1, 0, 0, 0,
2, 0, 0, 0,
4, 0, 0, 0,
42, 0, 0, 0,
0xDA, 0x0F, 0x49, 0x40, // 3.141...
3, 'P', 'i', '!'};
// clang-format on
RawQueue data(Data, Size);
std::cout << "String: " << call(&data, greeter) << std::endl;
std::cout << "Integers: " << call(&data, adder) << std::endl;
call(&data, mixed);
call(&data, []() { std::cout << "Nothing to do!" << std::endl; });
return 0;
}
Prints:
String: hello Ada
Integers: 7
Mixed: 42, 3.14159, Pi!
Nothing to do!

How do I replace an item in a multi index container without affecting the insertion order?

I have a multi index container with four indexes. One of the indexes is a random access index, used to maintain the insertion order. When a property on an element of the container is updated externally, I would like the relevant index to be updated. However, I would like to preserve the order of insertion.
I would like to know whether the order of insertion will be affected if I replace the value in question. If not, how can I achieve this?
I would expect modify() to work here. Let me try it out and show an example:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <iostream>
struct Data
{
int i;
std::string index1;
friend std::ostream& operator<<(std::ostream& os, Data const& v) {
return os << "{ " << v.i << ", '" << v.index1 << "' }";
}
};
namespace bmi = boost::multi_index;
using Table = bmi::multi_index_container<
Data,
bmi::indexed_by<
bmi::random_access<>,
bmi::ordered_unique<bmi::member<Data, std::string, &Data::index1> >
> >;
static std::ostream& operator<<(std::ostream& os, Table const& table) {
os << "insertion order: "; for(auto const& element : table) os << element << "; ";
os << "\nsecondary index: ";for(auto const& element : table.get<1>()) os << element << "; ";
return os << "\n";
}
int main()
{
Table table {
{ 42, "aap" },
{ 43, "noot" },
{ 44, "mies" }
};
std::cout << "Before:\n" << table << "\n";
table.modify(table.begin(), [](Data& v) { v.i *= v.i; });
std::cout << "Edit 1:\n" << table << "\n";
table.modify(table.begin()+2, [](Data& v) { v.index1 = "touched"; });
std::cout << "Edit 2:\n" << table << "\n";
}
Prints
Before:
insertion order: { 42, 'aap' }; { 43, 'noot' }; { 44, 'mies' };
secondary index: { 42, 'aap' }; { 44, 'mies' }; { 43, 'noot' };
Edit 1:
insertion order: { 1764, 'aap' }; { 43, 'noot' }; { 44, 'mies' };
secondary index: { 1764, 'aap' }; { 44, 'mies' }; { 43, 'noot' };
Edit 2:
insertion order: { 1764, 'aap' }; { 43, 'noot' }; { 44, 'touched' };
secondary index: { 1764, 'aap' }; { 43, 'noot' }; { 44, 'touched' };
Which is likely what you wanted?
See it Live On Coliru

In Boost Log, how do I format a custom severity_level using a format string?

I'm using boost log in my C++ program, and I have a custom severity_logger< severity_level > using a severity_level enum that I defined. Then I create my log sink with the format string "%TimeStamp% [%ThreadID%] %Severity% %Module% - %Message%" but it doesn't display the severity where I have %Severity% but instead is just blank in that position. For example, 2013-07-29 10:31 [0xDEADBEEF] my.Module - Hello World. What do I need to do in my format string to make it display the severity level?
Here's a portion of my code:
#define NUM_SEVERITY_LEVELS 6
enum severity_level
{
// These are deliberately the same levels that log4j uses
trace = 0,
debug = 1,
info = 2,
warning = 3,
error = 4,
fatal = 5
};
typedef src::severity_logger< severity_level > logger_t;
const char* severity_level_str[NUM_SEVERITY_LEVELS] = {
"TRACE",
"DEBUG",
"INFO",
"WARNING",
"ERROR",
"FATAL"
};
template< typename CharT, typename TraitsT >
std::basic_ostream< CharT, TraitsT >&
operator<< (
std::basic_ostream< CharT, TraitsT >& strm,
severity_level lvl
)
{
const char* str = severity_level_str[lvl];
if (lvl < NUM_SEVERITY_LEVELS && lvl >= 0)
strm << str;
else
strm << static_cast< int >(lvl);
return strm;
}
#define FORMAT_STRING "%TimeStamp% [%ThreadID%] %Severity% %Module% - %Message%"
boost::shared_ptr< sinks::synchronous_sink< sinks::text_file_backend > >
LOG_CREATE_SINK(const std::string& strLogFilename, bool fAutoFlush)
{
return logging::add_file_log(
keywords::file_name = strLogFilename,
keywords::open_mode = (std::ios_base::app | std::ios_base::out) & ~std::ios_base::in,
keywords::auto_flush = fAutoFlush,
keywords::format = FORMAT_STRING );
}
You should add
boost::log::register_simple_formatter_factory< severity_level, char >("Severity");
before calling LOG_CREATE_SINK method. Like this:
int main(int argc, char* argv[])
{
boost::log::register_simple_formatter_factory< severity_level, char >("Severity");
LOG_CREATE_SINK("log_file.txt", true);
logger_t logger;
BOOST_LOG_SEV(logger, trace)
<< "text message";
return 0;
}
Result:
[] TRACE - text message

Resources