Search code examples
c++googletestallocator

How to solve an unexpect std::allocator when compile code?


I defined a constructor of a class as below:

struct TestClass
{
    TestClass(std::uint8_t, std::vector<Type>)
    {
        //...
    }
};

Then I want to use google test to do a unit test, the compile error occurs when I try to construct an instance of TestClass, as below:

TEST(name1,name2)
{
    //...
    Type element;
    std::vector<Type> lst{element};
    TestClass instance(0, lst);
    //...
}

The gnu compiler reports:

"In function name1_name2_Test::TestBody()':test.cpp:(.text+0x165d): undefined reference toTestClass::TestClass(signed char, std::vector< Type, std::allocator< Type>)' collect2: error: ld returned 1 exit status"

Below is my evironment:

g++ version: 5.3.0
google test version: 1.7.0
the compile command: g++ -D_GLIBCXX_USE_CXX11_ABI=0 test.cpp -std=c++14 -lboost_system -lgtest -lgtest_main -lpthread

Have you ever met similar problem? Please give me some suggestions, thanks.

Below code can cause above error:

#include <gtest/gtest.h>

struct Element
{
    Element(const std::vector<std::uint8_t>& element) : element_(element){}
    std::vector<std::uint8_t> element_;
};

using ElementList = std::vector<Element>;

struct Information
{
    Information(std::uint8_t, ElementList) {}
    std::int8_t number_;
    ElementList eleLst_;
};

TEST(name1,name2)
{
    std::uint8_t number = 0;

    std::vector<std::uint8_t> vec{1,2,3,4};
    Element elem(vec);
    ElementList lst{elem};

    Information info(std::int8_t(0), lst);                      //false
}
GTEST_API_ int main(int argc, char **argv)
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

Below is compile message:

/tmp/ccUzsTfz.o: In function name1_name2_Test::TestBody()': test.cpp:(.text+0x130): undefined reference toInformation::Information(unsigned char, std::vector< Element, std::allocator< Element > >)'
collect2: error: ld returned 1 exit status


Solution

  • Your signature is:

    struct TestClass
    {
        TestClass(std::uint8_t, std::vector<Type>)
        {
            //...
        }
    };
    

    And the LINKER looks for:

    TestClass::TestClass(signed char, std::vector< Type>, std::allocator< Type>);
    

    Your TestClass' constructor definition does not contain an allocator-parameter!

    That's why there's no function instantiated containing the allocator-parameter and consequently it is not found by the linker.

    EDIT: Some more reference

    http://www.cplusplus.com/doc/tutorial/classes/ // Basics

    https://isocpp.org/wiki/faq/ctors // Good to know

    EDIT: There was some misunderstanding

    TestClass(signed char, std::vector<Type>)
    

    as the constructor is enough, if you use a standard allocator of type "Type"..

    See: http://de.cppreference.com/w/cpp/container/vector

    THis is the signature of the class:

    template<
        class T,
        class Allocator = std::allocator<T>
    > class vector;
    

    As you can see, it has a default template parameter assignment for Allocator, which is std::allocator.

    This way, you only have to specify an allocator In the template parameter list, if you have a custom allocator, i.e.:

    #include <iostream>
    #include <string>
    #include <vector>
    #include <memory>
    
    struct Type {};
    
    template <typename T>
    class MyBatchAllocator {
    
    };
    
    template <typename TAllocator = std::allocator<Type>>
    class TestClass {
        public:
            TestClass(signed char, const std::vector<Type, TAllocator>&) {
                // ...
        }
    };
    
    int main()
    {
        // main.cpp
        Type element;
        std::vector<Type, MyBatchAllocator<Type>> lst({ element });
        TestClass<MyBatchAllocator<Type>> tc(0, lst);
    }
    

    Otherwise, if you use standard allocators use this:

    int main() {
        Type element;
        std::vector<Type> lst2({ element });
        TestClass<> tc2(0, lst2); 
        // Yes, if TestClass is a template with a single 
        // defaulted template parameter the empty <> are required.
    }
    

    Appendix

    If you want to make your life with those templates easier, you could employ an alias:

    using DefaultTestClass = TestClass<>;
    

    and call it like:

    DefaultTestClass tc3(0, lst2);
    

    http://en.cppreference.com/w/cpp/language/type_alias