1
#include <iostream>
#include <vector>
#include <memory>

class Node{
public:
    static constexpr int data_size = sizeof(int);
};

class View{
public:
    View(int size){
    }
};

class Header: public Node{
public:
    void foo(){
        std::shared_ptr<View> v = std::make_shared<View>(data_size);
    }

    void bar(){
        std::shared_ptr<View> v(new View(data_size));
    }
    View bar1(){
        return View(data_size);
    }
    void bar2(){
        View *v = new View(data_size);
    }
    int bar3(){
        return data_size;
    }
};

int main() {

    Header *h = new Header();

    // This 1 lines below will produce the error
    h->foo();

    // These 4 lines are ok
    h->bar();
    h->bar1();
    h->bar2();
    h->bar3();

    return 0;
}

When call foo() , error below will occur :

/Applications/CLion.app/Contents/bin/cmake/bin/cmake --build /Users/everettjf/code/cpptest/cmake-build-debug --target all -- -j 8
Scanning dependencies of target cpptest
[ 50%] Building CXX object CMakeFiles/cpptest.dir/main.cpp.o
[100%] Linking CXX executable cpptest
Undefined symbols for architecture x86_64:
  "Node::data_size", referenced from:
      Header::foo() in main.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [cpptest] Error 1
make[1]: *** [CMakeFiles/cpptest.dir/all] Error 2
make: *** [all] Error 2

When I use new to initialize the shared_ptr ,it is ok.But when I use make_shared, the link error occurs.

Why std::make_shared different with new when construct with static constexpr member ?

My environment is macOS with Clion, CMakeList.txt is :

cmake_minimum_required(VERSION 3.6)
project(cpptest)
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES main.cpp)
add_executable(cpptest ${SOURCE_FILES})
everettjf
  • 116
  • 2
  • 8
  • foo function call is not giving error, i just checked http://cpp.sh/4r3ef – PapaDiHatti Apr 19 '17 at 03:56
  • oh,no. why? I just create a new project with Xcode. (macOS > command line tool) . And paste the code into main.cpp. Then build, the error occurs. @Kapil – everettjf Apr 19 '17 at 04:09
  • 2
    See [Undefined reference error for static constexpr member](http://stackoverflow.com/questions/40690260/undefined-reference-error-for-static-constexpr-member) – cpplearner Apr 19 '17 at 04:10
  • @cpplearner Thanks , it's almost the same question. In Xcode , the error can be fixed by static_cast like this code : `std::make_shared(static_cast(data_size));` – everettjf Apr 19 '17 at 05:48
  • @Kapil See here https://wandbox.org/permlink/y7yyLKD4x9YKLu5K , If I choose c++11 or c++14 ,the error occurs. And If I choose c++1z , no error. – everettjf Apr 19 '17 at 06:00

1 Answers1

0

Why new is working..

std::shared_ptr<View> v(new View(data_size));

In the above code (my guess is) the compiler substitutes data_size with the value itself. So it compiles and runs fine.

Why std::make_shared<>() fails ..

std::shared_ptr<View> v = std::make_shared<View>(data_size);

std::make_shared does something called perfect forwarding. And in the above case it needs to know the address of Node::data_size. Since you have not defined it anywhere, you linker can't find the symbols and throws the error.

To solve this problem, define the symbol Node::data_size in your code.

Abdus Khazi
  • 453
  • 3
  • 17
  • Why perfect forwarding needs to know the address of Node::data_size, it just works on two things first it should be template function and second it applies reference collapsing rules – PapaDiHatti Apr 19 '17 at 04:46
  • Maybe the perfect is not perfect ... – everettjf Apr 19 '17 at 05:54