dimanche 27 août 2017

Why is implicit conversion from const to non-const allowed?

Why does C++ allow the following code to compile?

std::unordered_map<std::string, int> m;
// ...
for (const std::pair<std::string, int>& p: m)
{
    // ...
}

According to Scott Meyers' Effective Modern C++ (p. 40-41):

[...] the key part of a std::unordered_map is const, so the type of std::pair in the hash table (which is what a std::unordered_map is) isn’t std::pair<std::string, int>, it's std::pair <const std::string, int>. But that's not the type declared for the variable p in the loop above. As a result, compilers will strive to find a way to convert std::pair<const std::string, int> objects (i.e., what’s in the hash table) to std::pair<std::string, int> objects (the declared type for p). They’ll succeed by creating a temporary object of the type that p wants to bind to by copying each object in m, then binding the reference p to that temporary object. At the end of each loop iteration, the temporary object will be destroyed. If you wrote this loop, you'd likely be surprised by this behavior, because you'd almost certainly intend to simply bind the reference p to each element in m.

What is the benefit of allowing this implicit conversion? Is there some common use case where the developer would expect / prefer this implicit conversion (rather than getting a compiler error)?

SIGSEGV in destructor that I don't call myself?

I have this piece of code:

#include <vector>
using std::vector;

class Material {
public:
    virtual ~Material() {}
};

class DiffuseMaterial : public Material {
public:
    DiffuseMaterial() {}
};

class Sphere {
public:
    vector<Material*> materials = {};
    ~Sphere() { for (int i = 0; i < (int)materials.size(); ++i) delete materials[i]; }
    void addMaterial(Material* mat) { materials.push_back(mat); }
};

int main(int argc, char *argv[]) {
    vector<Sphere> models;
    models.push_back(Sphere());
    models[0].addMaterial(new DiffuseMaterial());
    models.push_back(Sphere());
    models[1].addMaterial(new DiffuseMaterial());

    return 0;
}

It seems that when I declare the models vector, a destructor is called. In this destructor, we try to call the destructor of the element type, which throws a SIGSEGV. Why is this happening?

Surprisingly, if I move the push_back(Sphere()) statements next to each other, and call addMaterial after them, it works fine. The SIGSEGV appears only when interleaving these calls.

Any idea why this happens?

Here is the gdb call stack. Frame #5 is the call to the vector destructor, and frame #0 is the call to the Sphere destructor.

#0  0x0000000000400cb5 in Sphere::~Sphere (this=0x617c80, __in_chrg=<optimized out>) at render2.cpp:17
#1  0x0000000000401e13 in std::_Destroy<Sphere> (__pointer=0x617c80) at /usr/include/c++/6.3.1/bits/stl_construct.h:93
#2  0x0000000000401a83 in std::_Destroy_aux<false>::__destroy<Sphere*> (__first=0x617c80, __last=0x617cb0) at /usr/include/c++/6.3.1/bits/stl_construct.h:103
#3  0x0000000000401694 in std::_Destroy<Sphere*> (__first=0x617c80, __last=0x617cb0) at /usr/include/c++/6.3.1/bits/stl_construct.h:126
#4  0x00000000004012b1 in std::_Destroy<Sphere*, Sphere> (__first=0x617c80, __last=0x617cb0) at /usr/include/c++/6.3.1/bits/stl_construct.h:151
#5  0x0000000000400e77 in std::vector<Sphere, std::allocator<Sphere> >::~vector (this=0x7fffffffda50, __in_chrg=<optimized out>) at /usr/include/c++/6.3.1/bits/stl_vector.h:426
#6  0x0000000000400b7b in main (argc=1, argv=0x7fffffffdba8) at render2.cpp:22

Are all

Notice that std::normal_distribution::operator() is not const, nor does it behave in a const way. (Some other distributions have () operators that behave in a const way, but are also not defined to be const).

Given that std::normal_distribution::operator() is not const, is it still safe to use the same normal_distribution object across multiple threads? Is it safe for all distributions in the random header?

C++11 header files can't be found mingw-w64 Eclipse Oxygen?

I installed minGW-w64 on my Windows machine (the file I unzipped was called x86_64-7.1.0-release-posix-seh-rt_v5-rev2.zip, and I added the bin to my path already), and I'm using it with Eclipse. It works fine for almost everything, but it seems to run into issues with C++11 code. The code that's giving me errors is below.

#include <iostream>
#include <random>
using namespace std;

int main(){
    default_random_engine generator;
    normal_distribution<double> a(5.0,2.0);
    return 0;
}

Basically, Eclipse can't find the default_random_engine or normal_distribution. It finds the header file, but its the wrong header file, which I pasted below (the right one is here: http://ift.tt/2wB2HAy). How can I make Eclipse find the right file and have C++11 support?

#ifndef _GLIBCXX_RANDOM
#define _GLIBCXX_RANDOM 1

#pragma GCC system_header

#if __cplusplus < 201103L
# include <bits/c++0x_warning.h>
#else

#include <cmath>
#include <cstdlib>
#include <string>
#include <iosfwd>
#include <limits>
#include <debug/debug.h>
#include <type_traits>

#ifdef _GLIBCXX_USE_C99_STDINT_TR1

#include <cstdint> // For uint_fast32_t, uint_fast64_t, uint_least32_t
#include <bits/random.h>
#include <bits/opt_random.h>
#include <bits/random.tcc>

#endif // _GLIBCXX_USE_C99_STDINT_TR1

#endif // C++11

#endif // _GLIBCXX_RANDOM

Defeated by vector

Coming back to C++ after many years; trying to catch up to C++11 & 14. I've read about rvalues and move semantics. I thought I understood the concept. Apparently not. I've looked at dozens of examples. But I simply can't get my code to compile. I must be missing something obvious in the examples. I always get the error about the copy ctor being deleted because of unique_ptr having a user-declared move ctor. There's obviously something I'm missing about the concept, but I can't figure out what it is. Here's the code, stripped down to its essence:

#include <utility>
#include <vector>

int main(int, char*[]) {
  auto oneInt{std::make_unique<int>(0)};
  auto someInts{std::vector<std::unique_ptr<int>>{std::move(oneInt)}};

  return 0;
}

What am I doing wrong?

Edit: Here's the error from this particular code. Note that I've tried every variation on the code that I can think of, with varying results, but the basic problem is always the same: copy ctor deleted because unique_ptr has a user-declared move ctor.

/Applications/http://ift.tt/2wA3gKI: error: call to implicitly-deleted copy constructor of
      'std::__1::unique_ptr<int, std::__1::default_delete<int> >'
            ::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
                              ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Applications/http://ift.tt/2wfSxTn: note: in instantiation of function template
      specialization 'std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > >::construct<std::__1::unique_ptr<int, std::__1::default_delete<int> >,
      const std::__1::unique_ptr<int, std::__1::default_delete<int> > &>' requested here
            {__a.construct(__p, _VSTD::forward<_Args>(__args)...);}
                 ^
/Applications/http://ift.tt/2wAef6Q: note: in instantiation of function template
      specialization 'std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > > >::__construct<std::__1::unique_ptr<int,
      std::__1::default_delete<int> >, const std::__1::unique_ptr<int, std::__1::default_delete<int> > &>' requested here
            {__construct(__has_construct<allocator_type, _Tp*, _Args...>(),
             ^
/Applications/http://ift.tt/2wfCFjF: note: in instantiation of function template
      specialization 'std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > > >::construct<std::__1::unique_ptr<int,
      std::__1::default_delete<int> >, const std::__1::unique_ptr<int, std::__1::default_delete<int> > &>' requested here
                construct(__a, _VSTD::__to_raw_pointer(__begin2), *__begin1);
                ^
/Applications/http://ift.tt/2wAcmHk: note: in instantiation of function template
      specialization 'std::__1::allocator_traits<std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > > >::__construct_range_forward<const
      std::__1::unique_ptr<int, std::__1::default_delete<int> > *, std::__1::unique_ptr<int, std::__1::default_delete<int> > *>' requested here
    __alloc_traits::__construct_range_forward(__a, __first, __last, this->__end_);
                    ^
/Applications/http://ift.tt/2wfARXJ: note: in instantiation of function template
      specialization 'std::__1::vector<std::__1::unique_ptr<int, std::__1::default_delete<int> >, std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> >
      > >::__construct_at_end<const std::__1::unique_ptr<int, std::__1::default_delete<int> > *>' requested here
        __construct_at_end(__il.begin(), __il.end(), __il.size());
        ^
virtual.cpp:6:21: note: in instantiation of member function 'std::__1::vector<std::__1::unique_ptr<int, std::__1::default_delete<int> >,
      std::__1::allocator<std::__1::unique_ptr<int, std::__1::default_delete<int> > > >::vector' requested here
      auto someInts{std::vector<std::unique_ptr<int>>{std::move(oneInt)}};
                    ^
/Applications/http://ift.tt/2wzXx7V: note: copy constructor is implicitly deleted because
      'unique_ptr<int, std::__1::default_delete<int> >' has a user-declared move constructor
    _LIBCPP_INLINE_VISIBILITY unique_ptr(unique_ptr&& __u) _NOEXCEPT

Why my c++ move constructor was not called? [duplicate]

This question already has an answer here:

I wrote a simple class called Str and overwrote its constructor, copy constructor and move constructor.

class Str
{
public:
    Str(const char* s) :m_data(NULL)
    {
        printf("constructor\n");
        int size = strlen(s) + 1;
        m_data = new char[size];
        strncpy_s(m_data, size, s, size);
    }

    Str(const Str &s) 
    {
        printf("copy constructor\n");
        int size = strlen(s.m_data) + 1;
        m_data = new char[size];
        strncpy_s(m_data, size, s.m_data, size);
    }

    Str(Str &&s)
    {
        printf("move constructor\n");
        m_data = s.m_data;
        s.m_data = NULL;
    }

public:
    char* m_data;
};

Now I have such a function who wants to call its move constructor:

void speak(Str &&s)
{
}
Str getStr()
{
    Str s("cat");
    return s;
}

If I try this way, move constructor can be called.

speak(getStr());

Its output is :

constructor
move constructor

It's because getStr() is a temporary value, so move constructor was called, right? But if I try this way, it cannot.

speak(Str("cat"));

Its output is :

constructor

What I don't understand is that Str("cat") is a temporary value as well. But it only called constructor! Why??

C++ multi line define directive error

After reading this question, I have the following code,

#define OSSPECIFICHANDLERTYPE { \
#ifdef SDL_VIDEO_DRIVER_WINDOWS \
HWND                            \
#endif                          \
#if defined(SDL_VIDEO_DRIVER_X11)   \
Window                              \
#endif                              \
#if defined(SDL_VIDEO_DRIVER_COCOA) \
NSWindow*                       \
#endif }

OSSPECIFICHANDLERTYPE s_hWndBase;

But it gives the following errors,

First,

main.cpp:64:1: error: expected expression

OSSPECIFICHANDLERTYPE s_hWndBase; ^

Second,

main.cpp:53:33: note: expanded from macro 'OSSPECIFICHANDLERTYPE' #define OSSPECIFICHANDLERTYPE { \

And third,

main.cpp:64:23: error: use of undeclared identifier 's_hWndBase' OSSPECIFICHANDLERTYPE s_hWndBase;

So where is the problem and how can I solve this ?