C++11 MinGW 4.9.1 shared_ptr and const static class field result "Undefined reference"

295 views Asked by At
#include <memory>

class CItem
{
  private:
    int m_inner;
  public:
    static const int CAP = 1;
    CItem(int temp) : m_inner(temp) {}
};

typedef std::shared_ptr<CItem> TPItem;

int main()
{
  int tttt = CItem::CAP;
  CItem *temp = new CItem(CItem::CAP);
  TPItem temp2(temp);
  TPItem temp3 = std::make_shared<CItem>(tttt);
  TPItem temp4 = std::make_shared<CItem>(CItem::CAP); //On MinGW there error: "undefined reference to `CItem::CAP'"

  return 0;
}
  • on Visual Studio 2012 it work normal.
  • on minGW32 4.9.1 it say "undefined reference" for static const field of class when try create shared pointer with make_shared.
  • other methods:
  • copy this field to int and create shared with this int - work.
  • create class object with new - work.

Where my fault?

1

There are 1 answers

3
Shafik Yaghmour On BEST ANSWER

This is because CItem::CAP is odr-used by std::make_shared (emphasis mine):

Informally, an object is odr-used if its address is taken, or a reference is bound to it, and a function is odr-used if a function call to it is made or its address is taken. If an object or a function is odr-used, its definition must exist somewhere in the program; a violation of that is a link-time error.

Since std::make_shared takes its arguments by reference, this counts as an odr-use.

which means you are required to provide an out of class definition as well:

const int CItem::CAP  ;

or avoid the odr-use such as in this case:

TPItem temp3 = std::make_shared<CItem>(tttt) ;

For reference the draft C++11 standard section 3.2 [basic.def.odr] says:

An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof. A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied.

CItem::CAP is a constant expression and in all the cases except this one:

TPItem temp4 = std::make_shared<CItem>(CItem::CAP);

the lvalue-to-rvalue conversion is applied immediately.