Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uniform initialization causes runtime error in C++

I'm huge fan of uniform initialization and I'm using it in most cases when i want to construct initialized variable. Recently, I came across weird error while i was constructing variable of type cv::Mat.

cv::Mat lookUpTable( 1, 256, CV_8U );
uchar* p = lookUpTable.ptr();

for( int i = 0; i < 256; ++i )
{
    p[i] = cv::saturate_cast<uchar>( pow( i / 255.0, gamma ) * 255.0 );
}

While this implementation works well, if uniform initialization is used

cv::Mat lookUpTable{ 1, 256, CV_8U };

following error shows up

malloc_consolidate(): invalid chunk size

I'm still not really sure what happes. Is different constructor (than supposed) used ? Can somebody explain further, please ?

like image 617
kocica Avatar asked Dec 11 '18 15:12

kocica


People also ask

What is uniform initialization in C?

Uniform Initialization in C++ The uniform initialization is a feature that permits the usage of a consistent syntax to initialize variables and objects which are ranging from primitive type to aggregates. In other words, it introduces brace-initialization that applies braces ({}) to enclose initializer values.

What is runtime error in c programming?

Runtime Error: A runtime error in a program is an error that occurs while the program is running after being successfully compiled.


2 Answers

cv::Mat lookUpTable{ 1, 256, CV_8U } calls a different constructor than cv::Mat lookUpTable( 1, 256, CV_8U ). cv::Mat lookUpTable{ 1, 256, CV_8U } is direct-list-initialization and since cv::Mat has a constructor accepting a std::initlizer_list, that constructor will be called instead of the 3 parameter one the first call does. This means you have a matrix that contains the elements { 1, 256, CV_8U }, instead of a 256 element matrix.

Nicolai Josuttis has a really nice talk at CppCon2018 about the "uniformity" of uniform initialization: https://www.youtube.com/watch?v=7DTlWPgX6zs

like image 164
NathanOliver Avatar answered Sep 24 '22 17:09

NathanOliver


Using {...} to construct an object is called "list-initialization".

cv::Mat provides a constructor taking std::initializer_list: https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/mat.hpp#L1007

There is a special rule in overload resolution that always gives priority to constructors taking std::initializer_list if list-initialization is used, regardless of the existence of other constructors which might require less implicit conversions.

Calling cv::Mat(...) is completely different from cv::Mat{...}.


My mental model for this is: if the object you're constructing is a container, then {...} will likely behave differently from (...), therefore you should be careful. Otherwise, prefer {...}.

like image 36
Vittorio Romeo Avatar answered Sep 24 '22 17:09

Vittorio Romeo