Skip to content

Commit 1d17e40

Browse files
Merge pull request #1926 from arcaneframework/dev/gg-simplify-memory-management-in-di
Simplify memory management in Dependency Injection
2 parents 2c18a2a + cab10f7 commit 1d17e40

File tree

3 files changed

+75
-88
lines changed

3 files changed

+75
-88
lines changed

arcane/src/arcane/utils/DependencyInjection.cc

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ class Injector::Impl
7070

7171
public:
7272

73+
// Il faut conserver une instance de FactoryInfo pour éviter sa
74+
// destruction prématurée car les instances dans m_factories en ont besoin.
7375
UniqueArray<Ref<impl::IInstanceFactory>> m_factories;
76+
UniqueArray<impl::FactoryInfo> m_factories_info;
7477
};
7578

7679
/*---------------------------------------------------------------------------*/
@@ -159,16 +162,23 @@ _doError1(const String& message, int nb_value)
159162
/*---------------------------------------------------------------------------*/
160163
/*---------------------------------------------------------------------------*/
161164

162-
class FactoryInfo::Impl
165+
class FactoryInfoImpl
163166
{
164167
public:
165-
Impl(const ProviderProperty& property)
168+
169+
FactoryInfoImpl(const ProviderProperty& property)
166170
: m_property(property)
167171
, m_name(property.name())
168172
{
169173
}
170174

171175
public:
176+
177+
bool hasName(const String& str) const { return str == m_name; }
178+
void fillWithImplementationNames(Array<String>& names) const { names.add(m_name); }
179+
180+
public:
181+
172182
const ProviderProperty m_property;
173183
UniqueArray<Ref<IInstanceFactory>> m_factories;
174184
String m_name;
@@ -179,22 +189,13 @@ class FactoryInfo::Impl
179189

180190
FactoryInfo::
181191
FactoryInfo(const ProviderProperty& property)
182-
: m_p{ new Impl(property) }
192+
: m_p(std::make_shared<FactoryInfoImpl>(property))
183193
{
184194
}
185195

186196
/*---------------------------------------------------------------------------*/
187197
/*---------------------------------------------------------------------------*/
188198

189-
FactoryInfo::
190-
~FactoryInfo()
191-
{
192-
delete m_p;
193-
}
194-
195-
/*---------------------------------------------------------------------------*/
196-
/*---------------------------------------------------------------------------*/
197-
198199
void FactoryInfo::
199200
addFactory(Ref<IInstanceFactory> f)
200201
{
@@ -207,16 +208,7 @@ addFactory(Ref<IInstanceFactory> f)
207208
bool FactoryInfo::
208209
hasName(const String& str) const
209210
{
210-
return str == m_p->m_name;
211-
}
212-
213-
/*---------------------------------------------------------------------------*/
214-
/*---------------------------------------------------------------------------*/
215-
216-
void FactoryInfo::
217-
fillWithImplementationNames(Array<String>& names) const
218-
{
219-
names.add(m_p->m_name);
211+
return m_p->hasName(str);
220212
}
221213

222214
/*---------------------------------------------------------------------------*/
@@ -255,11 +247,11 @@ fillWithGlobalFactories()
255247
Integer i = 0;
256248
while (g) {
257249
auto func = g->infoCreatorWithPropertyFunction();
258-
impl::FactoryInfo* fi = nullptr;
259-
if (func)
260-
fi = (*func)(g->property());
261-
if (fi)
262-
m_p->m_factories.addRange(fi->m_p->m_factories);
250+
if (func) {
251+
impl::FactoryInfo fi = (*func)(g->property());
252+
m_p->m_factories_info.add(fi);
253+
m_p->m_factories.addRange(fi.m_p->m_factories);
254+
}
263255

264256
g = g->nextRegisterer();
265257
++i;
@@ -311,7 +303,7 @@ _iterateFactories(const String& factory_name, IFactoryVisitorFunctor* functor) c
311303
Int32 nb_constructor_arg = f->nbConstructorArg();
312304
if (nb_constructor_arg >= 0 && nb_constructor_arg != nb_instance)
313305
continue;
314-
if (has_no_name || f->factoryInfo()->hasName(factory_name)) {
306+
if (has_no_name || f->factoryInfoImpl()->hasName(factory_name)) {
315307
if (functor->execute(f))
316308
return;
317309
}
@@ -363,7 +355,7 @@ _printValidImplementationAndThrow(const TraceInfo& ti,
363355
for (Int32 i = 0, n = _nbFactory(); i < n; ++i) {
364356
impl::IInstanceFactory* f = _factory(i);
365357
if (filter_func(f)) {
366-
f->factoryInfo()->fillWithImplementationNames(valid_names);
358+
f->factoryInfoImpl()->fillWithImplementationNames(valid_names);
367359
}
368360
};
369361
String message = String::format("No implementation named '{0}' found", implementation_name);

arcane/src/arcane/utils/internal/DependencyInjection.h

Lines changed: 51 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class Injector;
4848
namespace Arcane::DependencyInjection::impl
4949
{
5050
class FactoryInfo;
51+
class FactoryInfoImpl;
5152
class IInstanceFactory;
5253
template <typename InterfaceType>
5354
class IConcreteFactory;
@@ -337,12 +338,40 @@ class ARCANE_UTILS_EXPORT IInstanceFactory
337338
public:
338339

339340
virtual InjectedInstanceRef createGenericReference(Injector& injector, const String& name) = 0;
341+
virtual const FactoryInfoImpl* factoryInfoImpl() const = 0;
342+
virtual ConcreteFactoryTypeInfo concreteFactoryInfo() const = 0;
343+
virtual Int32 nbConstructorArg() const = 0;
344+
};
340345

341-
virtual const FactoryInfo* factoryInfo() const = 0;
346+
/*---------------------------------------------------------------------------*/
347+
/*---------------------------------------------------------------------------*/
348+
/*!
349+
* \internal
350+
* \brief Informations pour une fabrique.
351+
*/
352+
class ARCANE_UTILS_EXPORT FactoryInfo
353+
{
354+
friend class Arcane::DependencyInjection::Injector;
342355

343-
virtual ConcreteFactoryTypeInfo concreteFactoryInfo() const = 0;
356+
private:
344357

345-
virtual Int32 nbConstructorArg() const = 0;
358+
explicit FactoryInfo(const ProviderProperty& property);
359+
360+
public:
361+
362+
static FactoryInfo create(const ProviderProperty& property, const char* file_name, int line_number)
363+
{
364+
ARCANE_UNUSED(file_name);
365+
ARCANE_UNUSED(line_number);
366+
return FactoryInfo(property);
367+
}
368+
void addFactory(Ref<IInstanceFactory> f);
369+
bool hasName(const String& str) const;
370+
const FactoryInfoImpl* _impl() const { return m_p.get(); }
371+
372+
private:
373+
374+
std::shared_ptr<FactoryInfoImpl> m_p;
346375
};
347376

348377
/*---------------------------------------------------------------------------*/
@@ -367,10 +396,14 @@ template <typename InterfaceType>
367396
class InstanceFactory
368397
: public AbstractInstanceFactory
369398
{
399+
// NOTE: On ne conserve pas une instance de 'FactoryInfo'
400+
// mais uniquement son implémentation pour éviter des références croisées
401+
// avec le std::shared_ptr.
402+
370403
public:
371404

372-
InstanceFactory(FactoryInfo* si, IConcreteFactory<InterfaceType>* sub_factory)
373-
: m_factory_info(si)
405+
InstanceFactory(const FactoryInfoImpl* si, IConcreteFactory<InterfaceType>* sub_factory)
406+
: m_factory_info_impl(si)
374407
, m_sub_factory(sub_factory)
375408
{
376409
}
@@ -390,9 +423,9 @@ class InstanceFactory
390423
return _createReference(injector);
391424
}
392425

393-
const FactoryInfo* factoryInfo() const override
426+
const FactoryInfoImpl* factoryInfoImpl() const override
394427
{
395-
return m_factory_info;
428+
return m_factory_info_impl;
396429
}
397430

398431
ConcreteFactoryTypeInfo concreteFactoryInfo() const override
@@ -407,8 +440,8 @@ class InstanceFactory
407440

408441
protected:
409442

410-
FactoryInfo* m_factory_info;
411-
IConcreteFactory<InterfaceType>* m_sub_factory;
443+
const FactoryInfoImpl* m_factory_info_impl = nullptr;
444+
IConcreteFactory<InterfaceType>* m_sub_factory = nullptr;
412445

413446
private:
414447

@@ -460,44 +493,6 @@ class IConcreteFactory
460493
virtual Ref<InterfaceType> createReference(Injector&) = 0;
461494
};
462495

463-
/*---------------------------------------------------------------------------*/
464-
/*---------------------------------------------------------------------------*/
465-
/*!
466-
* \internal
467-
* \brief Informations pour une fabrique.
468-
*/
469-
class ARCANE_UTILS_EXPORT FactoryInfo
470-
{
471-
friend class Arcane::DependencyInjection::Injector;
472-
class Impl;
473-
474-
public:
475-
476-
FactoryInfo(const FactoryInfo&) = delete;
477-
FactoryInfo& operator=(const FactoryInfo&) = delete;
478-
~FactoryInfo();
479-
480-
private:
481-
482-
explicit FactoryInfo(const ProviderProperty& property);
483-
484-
public:
485-
486-
static FactoryInfo* create(const ProviderProperty& property, const char* file_name, int line_number)
487-
{
488-
ARCANE_UNUSED(file_name);
489-
ARCANE_UNUSED(line_number);
490-
return new FactoryInfo(property);
491-
}
492-
void addFactory(Ref<IInstanceFactory> f);
493-
bool hasName(const String& str) const;
494-
void fillWithImplementationNames(Array<String>& names) const;
495-
496-
private:
497-
498-
Impl* m_p = nullptr;
499-
};
500-
501496
/*---------------------------------------------------------------------------*/
502497
/*---------------------------------------------------------------------------*/
503498

@@ -516,7 +511,7 @@ class ARCANE_UTILS_EXPORT GlobalRegisterer
516511

517512
public:
518513

519-
typedef FactoryInfo* (*FactoryCreateFunc)(const ProviderProperty& property);
514+
typedef FactoryInfo (*FactoryCreateFunc)(const ProviderProperty& property);
520515

521516
public:
522517

@@ -914,7 +909,7 @@ class InterfaceListRegisterer
914909
* créer une instance de \a ConcreteType via le constructeur \a ConstructorType
915910
*/
916911
template <typename ConcreteType, typename ConstructorType> void
917-
registerFactory(FactoryInfo* si)
912+
registerFactory(FactoryInfo& si)
918913
{
919914
_registerFactory<ConcreteType, ConstructorType, Interfaces...>(si);
920915
}
@@ -924,10 +919,10 @@ class InterfaceListRegisterer
924919
template <typename ConcreteType, typename ConstructorType,
925920
typename InterfaceType, typename... OtherInterfaces>
926921
void
927-
_registerFactory(FactoryInfo* fi)
922+
_registerFactory(FactoryInfo& fi)
928923
{
929924
auto* factory = new ConcreteFactory<InterfaceType, ConcreteType, ConstructorType>();
930-
fi->addFactory(createRef<InstanceFactory<InterfaceType>>(fi, factory));
925+
fi.addFactory(createRef<InstanceFactory<InterfaceType>>(fi._impl(), factory));
931926
// Applique récursivement pour les autres interfaces si nécessaire
932927
if constexpr (sizeof...(OtherInterfaces) > 0)
933928
_registerFactory<ConcreteType, ConstructorType, OtherInterfaces...>(fi);
@@ -949,7 +944,7 @@ class InjectionRegisterer
949944

950945
//! Enregistre dans \a si les fabriques correspondentes aux constructeurs \a Constructors
951946
template <typename... Constructors> void
952-
registerProviderInfo(FactoryInfo* si, const Constructors&... args)
947+
registerProviderInfo(FactoryInfo& si, const Constructors&... args)
953948
{
954949
_create(si, args...);
955950
}
@@ -963,14 +958,14 @@ class InjectionRegisterer
963958

964959
//! Surcharge pour 1 constructeur
965960
template <typename ConstructorType> void
966-
_create(FactoryInfo* si, const ConstructorType&)
961+
_create(FactoryInfo& si, const ConstructorType&)
967962
{
968963
m_interface_list.template registerFactory<ConcreteType, ConstructorType>(si);
969964
}
970965

971966
//! Surcharge pour 2 constructeurs ou plus
972967
template <typename C1, typename C2, typename... OtherConstructors>
973-
void _create(FactoryInfo* si, const C1& c1, const C2& c2, const OtherConstructors&... args)
968+
void _create(FactoryInfo& si, const C1& c1, const C2& c2, const OtherConstructors&... args)
974969
{
975970
_create<C1>(si, c1);
976971
// Applique la récursivité sur les types restants
@@ -1000,10 +995,10 @@ class InjectionRegisterer
1000995
#define ARCANE_DI_REGISTER_PROVIDER(t_class, t_provider_property, t_interfaces, ...) \
1001996
namespace \
1002997
{ \
1003-
Arcane::DependencyInjection::impl::FactoryInfo* \
998+
Arcane::DependencyInjection::impl::FactoryInfo \
1004999
ARCANE_JOIN_WITH_LINE(arcaneCreateDependencyInjectionProviderInfo##t_class)(const Arcane::DependencyInjection::ProviderProperty& property) \
10051000
{ \
1006-
auto* si = Arcane::DependencyInjection::impl::FactoryInfo::create(property, __FILE__, __LINE__); \
1001+
auto si = Arcane::DependencyInjection::impl::FactoryInfo::create(property, __FILE__, __LINE__); \
10071002
Arcane::DependencyInjection::impl::InjectionRegisterer<t_class, t_interfaces> injection_registerer; \
10081003
injection_registerer.registerProviderInfo(si, __VA_ARGS__); \
10091004
return si; \

arcane/src/arcane/utils/tests/TestDependencyInjection.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -339,13 +339,13 @@ TEST(DependencyInjection, ConstructorCall)
339339

340340
try {
341341
Injector injector;
342-
IB* ib{ new BImpl() };
343-
injector.bind(ib);
342+
std::unique_ptr<IB> ib{ std::make_unique<BImpl>() };
343+
injector.bind(ib.get());
344344
injector.bind(x);
345345
Ref<IA2> a2 = c2f.createReference(injector);
346346
ARCANE_CHECK_POINTER(a2.get());
347347
ASSERT_EQ(a2->value(), 3);
348-
ASSERT_EQ(a2->bValue(), ib);
348+
ASSERT_EQ(a2->bValue(), ib.get());
349349
}
350350
catch (const Exception& ex) {
351351
std::cerr << "ERROR=" << ex << "\n";

0 commit comments

Comments
 (0)