navirius
navirius

Reputation: 317

Problem using boost::object_pool boost version 1.56 with visual studio 2019

I am trying to convert boost::object_pool usage on my old project to new visual studio 2019 project, I am using boost version 1.56

ObjectPool.h

class BOOST_OBJECT_POOL_CHECKER
{
  boost::object_pool< T > m_sObjectPool;
  
  template <class Arg1>
  T* contruct(Arg1& sArg1)
  {
     T* temp = m_sObjectPool.construct(sArg1);
     return temp;
  }
}

MaterialServer.h

class MaterialServer
{
   MaterialServer(dword serviceType, std::string path);
   Material* NEW_MATERIAL();
}

Material.h

class Material
{
  BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;

  Material(MaterialServer* pMatServer);
  
}

Material.cpp

Material* MaterialServer::NEW_MATERIAL()
{
   //Material* returnMaterial = m_poolMATERIAL.construct(this); << error on vs2019, not correct parameter
   Material* returnMaterial = m_poolMATERIAL.construct(*this);
}

got first error

boost_1_56\boost\pool\detail\pool_construct_simple.ipp(19,1): error C2664: 'Material::Material(MaterialServer*)': cannot convert argument 1 from 'const T0' to 'MaterialServer *'
ObjectPool.h(68): message : see reference to function template instantiation 'Material *boost::object_pool<T,boost::default_user_allocator_new_delete>::construct<Arg1>(const T0 &)' being compiled
        with
        [
            T=Material,
            Arg1=MaterialServer,
            T0=MaterialServer
        ]

should I need upgrade boost version? because previously this code compiled fine on vs2008, but not compiled on vs2019, this c++11 standard so confusing for me

can I get explanation this behavior?

Upvotes: 0

Views: 91

Answers (1)

sehe
sehe

Reputation: 392833

Frankly, this code cannot have compiled under any compiler.

Note: I'm ignoring numerous typos, omitted semi-colons, omitted template declarators, typedefs and access specifiers to focus on the real issues.

You're passing *this which is Material&. However, the contruct [sic] function takes a MaterialServer*.

So, in fact, the commented line was closer, and makes sense IFF it were a member of MaterialServer, not Material.

It would make a lot more sense, logically, for the material server to "create new materials", anyways, and almost works:

class Material {
  public:
    Material(MaterialServer* pMatServer);
};

class MaterialServer {
    BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;

  public:
    MaterialServer(dword serviceType, std::string path);
    Material* NEW_MATERIAL();
};

Material* MaterialServer::NEW_MATERIAL()
{
    Material* returnMaterial = m_poolMATERIAL.construct(this);
    return returnMaterial;
}

I say /almost/ because construct takes its argument by mutable reference. That won't compile here (this is NOT a mutable lvalue).

So, fixing that:

template <typename Arg1> T* construct(Arg1 sArg1) {
    return m_sObjectPool.construct(sArg1);
}

Or, more generically:

template <typename... Arg> T* construct(Arg&&... sArg) {
    return m_sObjectPool.construct(std::forward<Arg>(sArg)...);
}

We get "compiling code". We can't link it (the constructors aren't defined).

Adding some more imagined code:

Live On Coliru

#include <boost/pool/object_pool.hpp>
#include <iomanip>
#include <iostream>
#include <string>
#include <atomic>

using dword = uint32_t;

template <typename T> class BOOST_OBJECT_POOL_CHECKER {
    boost::object_pool<T> m_sObjectPool;

  public:
    template <typename... Arg> T* construct(Arg&&... sArg)
    {
        return m_sObjectPool.construct(std::forward<Arg>(sArg)...);
    }
};

class MaterialServer; // forward declare

class Material {
  public:
    Material(MaterialServer* pMatServer);
};

class MaterialServer {
    BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;

    dword _serviceType;
    std::string _path;

  public:
    MaterialServer(dword serviceType, std::string path)
        : _serviceType(serviceType)
        , _path(path)
    {
    }

    Material* NEW_MATERIAL();

    dword getServiceType() const { return _serviceType; }
    std::string_view getPath() const { return _path; }
};

Material* MaterialServer::NEW_MATERIAL()
{
    Material* returnMaterial = m_poolMATERIAL.construct(this);
    return returnMaterial;
}

Material::Material(MaterialServer* pMatServer)
{
    static std::atomic_int id{0};
    std::cout << "Material " << id++ << " from server ("
              << pMatServer->getServiceType() << ", "
              << std::quoted(pMatServer->getPath()) << ")\n";
}

int main() {
    MaterialServer a(123, "Material/a/resource");
    MaterialServer b(234, "Material/b/resource");

    a.NEW_MATERIAL();
    a.NEW_MATERIAL();
    b.NEW_MATERIAL();
    a.NEW_MATERIAL();
}

Prints

Material 0 from server (123, "Material/a/resource")
Material 1 from server (123, "Material/a/resource")
Material 2 from server (234, "Material/b/resource")
Material 3 from server (123, "Material/a/resource")

Upvotes: 0

Related Questions