I am going back to C++ after spending some time in memory-managed languages, and I'm suddently kinda lost as to what is the best way to implement dependency injection. (I am completely sold to DI because I found it to be the simplest way to make test-driven design very easy).
我在内存管理语言上花了一些时间后回到C ++,而且我突然想知道实现依赖注入的最佳方法是什么。 (我完全卖给DI,因为我发现它是使测试驱动设计变得非常简单的最简单方法)。
Now, browsing SO and google got me quite a number of opinions on the matter, and I'm a bit confused.
现在,浏览SO和谷歌在这件事上得到了很多意见,我有点困惑。
As an answer to this question, Dependency injection in C++ , someone suggested that you should not pass raw pointers around, even for dependency injection. I understand it is related to ownership of the objects.
作为这个问题的答案,C ++中的依赖注入,有人建议你不要传递原始指针,即使是依赖注入。据我所知,这与对象的所有权有关。
Now, ownership of objects is also tackled (although not into enough details to my state ;) ) in the infamous google style guide : http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Smart_Pointers
现在,在臭名昭着的谷歌风格指南中,也解决了对象的所有权(尽管我的州没有足够的细节;)):http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Smart_Pointers
So what I understand is that in order to make it clearer which object has ownership of which other objects, you should avoid passing raw pointers around. In particular, it seems to be against this kind of coding :
所以我的理解是,为了使哪个对象拥有其他对象的所有权更清楚,你应该避免传递原始指针。特别是,它似乎反对这种编码:
class Addict {
// Something I depend on (hence, the Addict name. sorry.)
Dependency * dependency_;
public:
Addict(Dependency * dependency) : dependency_(dependency) {
}
~Addict() {
// Do NOT release dependency_, since it was injected and you don't own it !
}
void some_method() {
dependency_->do_something();
}
// ... whatever ...
};
If Dependency is a pure virtual class (aka poor-men-Interface ), then this code makes it easy to inject a mock version of the Dependency (using something like google mock).
如果Dependency是一个纯虚拟类(又名穷人 - 接口),那么这个代码可以很容易地注入一个依赖的模拟版本(使用google mock之类的东西)。
The problem is, I don't really see the troubles I can get in with this kind of code, and why I should want to use anything else than raw pointers ! Is it that it is not clear where the dependency comes from ?
问题是,我真的没有看到这种代码可以解决的问题,以及为什么我应该使用除了原始指针以外的任何东西!是不是很清楚依赖来自何处?
Also, I read quite a few posts hinting that one should really be using references in this situation, so is this kind of code better ?
另外,我读了很多帖子暗示在这种情况下应该使用引用,这样的代码更好吗?
class Addict {
// Something I depend on (hence, the Addict name. sorry.)
const Dependency & dependency_;
public:
Addict(const Dependency & dependency) : dependency_(dependency) {
}
~Addict() {
// Do NOT release dependency_, since it was injected and you don't own it !
}
void some_method() {
dependency_.do_something();
}
// ... whatever ...
};
But then I get other, equally authoritive advices against using references as member : http://billharlan.com/pub/papers/Managing_Cpp_Objects.html
但后来我得到了其他同样权威的建议,反对使用引用作为成员:http://billharlan.com/pub/papers/Managing_Cpp_Objects.html
As you can see I am not exactly sure about the relative pros and cons of the various approaches, so I am bit confused. I am sorry if this has been discussed to death, or if it is only a matter of personnal choice and consistency inside a given project ... but any idea is welcome.
如你所见,我不确定各种方法的相对优缺点,所以我有点困惑。我很抱歉,如果这已经被讨论过死亡,或者只是在给定项目中只是个人选择和一致性的问题......但任何想法都是受欢迎的。
Thanks
PH
Answer's summary
(I don't know if it is good SO-tiquette to do this, but I'll had code example for what I gathered from answers...)
(我不知道这样做是不是很好,但是我会从答案中得到的代码示例...)
From the various responses, here what I'll probably end up doing in my case :
从各种回复中,我可能最终会在我的案例中做到:
- pass dependencies as reference (at least to make sure NULL is not possible)
- in the general case where copying is not possible, explicitely disallow it, and store dependencies as reference
- in the rarer case where copying is possible, store dependencies as RAW pointers
- let the creator of the dependencies (factory of some kind) decide between stack allocation of dynamic allocation (and in this case, management through a smart pointer)
- establish a convention to separate dependencies from own resources
传递依赖关系作为参考(至少确保不可能为NULL)
在无法进行复制的一般情况下,明确禁止复制,并将依赖关系存储为参考
在可以进行复制的罕见情况下,将依赖关系存储为RAW指针
让依赖项的创建者(某种工厂)决定动态分配的堆栈分配(在这种情况下,通过智能指针进行管理)
建立一个约定来将依赖关系与自己的资源分开
So I would end up with something like :
所以我最终会得到类似的东西:
class NonCopyableAddict {
Dependency & dep_dependency_;
// Prevent copying
NonCopyableAddict & operator = (const NonCopyableAddict & other) {}
NonCopyableAddict(const NonCopyableAddict & other) {}
public:
NonCopyableAddict(Dependency & dependency) : dep_dependency_(dep_dependency) {
}
~NonCopyableAddict() {
// No risk to try and delete the reference to dep_dependency_ ;)
}
//...
void so_some_stuff() {
dep_dependency_.some_function();
}
};
And for a copyable class :
对于可复制的课程:
class CopyableAddict {
Dependency * dep_dependency_;
public:
// Prevent copying
CopyableAddict & operator = (const CopyableAddict & other) {
// Do whatever makes sense ... or let the default operator work ?
}
CopyableAddict(const CopyableAddict & other) {
// Do whatever makes sense ...
}
CopyableAddict(Dependency & dependency) : dep_dependency_(&dep_dependency) {
}
~CopyableAddict() {
// You might be tempted to delete the pointer, but its name starts with dep_,
// so by convention you know it is not you job
}
//...
void so_some_stuff() {
dep_dependency_->some_function();
}
};
From what I understood, there is no way to express the intent of "I have a pointer to some stuff, but I don't own it" that the compiler can enforce. So I'll have to resort to naming convention here ...
根据我的理解,没有办法表达“我有一个指向某些东西的指针,但我不拥有它”,编译器可以强制执行。所以我不得不在这里诉诸命名约定......
Kept for reference
保持参考
As pointed by Martin, the following example does not solve the problem.
正如Martin指出的那样,以下示例并未解决问题。
Or, assuming I have a copy constructor, something like :
或者,假设我有一个复制构造函数,例如:
class Addict {
Dependency dependency_;
public:
Addict(const Dependency & dependency) : dependency_(dependency) {
}
~Addict() {
// Do NOT release dependency_, since it was injected and you don't own it !
}
void some_method() {
dependency_.do_something();
}
// ... whatever ...
};
7 个解决方案
#1
7
There is no hard and fast rule:
As people have mentioned using references inside objects can cause copy problems (and it does) so it is not a panacea, but for certain situation it can be useful (that is why C++ gives us the option to do it all these different ways). But using RAW pointers is really not an option. If you are dynamically allocating objects then you should always be maintaining them with smart pointers and your object should also be using smart pointers.
没有严格的规则:正如人们提到的,在对象中使用引用会导致复制问题(并且它确实存在)因此它不是灵丹妙药,但对于某些情况它可能是有用的(这就是为什么C ++给我们提供选项做所有这些不同的方式)。但是使用RAW指针实际上不是一个选择。如果您正在动态分配对象,那么您应该始终使用智能指针维护它们,并且您的对象也应该使用智能指针。
For people who demand examples: Streams are always passed and stored as references (as they can't be copied).
对于需要示例的人:Streams总是作为引用传递和存储(因为它们无法复制)。
Some Comments on your code examples:
您的代码示例的一些评论:
Example one and two
Your first example with pointers. Is basically the same as the second example using references. The difference being that a reference can not be NULL. When you pass a reference the object is already alive and thus should have a lifespan greater than the object you are testing already (If it was created on the stack) so it should be safe to keep a reference. If you are dynamically creating pointers as dependencies I would consider using boost::shared_pointer or std::auto_ptr depending if ownership of the dependency is shared or not.
你的第一个指针示例。与使用引用的第二个示例基本相同。不同之处在于引用不能为NULL。当您传递引用时,该对象已经存活,因此其寿命应该大于您正在测试的对象(如果它是在堆栈上创建的),那么保留引用应该是安全的。如果您动态创建指针作为依赖项,我会考虑使用boost :: shared_pointer或std :: auto_ptr,具体取决于是否共享依赖项的所有权。
Example Three:
I don't see any great use for your third example. This is because you can not use polymorphic types (If you pass an object derived from Dependency it will be sliced during the copy operation). Thus the code may as well be inside Addict rather than a separate class.
我认为你的第三个例子并没有什么用处。这是因为您不能使用多态类型(如果您传递从Dependency派生的对象,它将在复制操作期间被切片)。因此代码也可以在Addict中,而不是单独的类。
Bill Harlen: (http://billharlan.com/pub/papers/Managing%5FCpp%5FObjects.html)
Not to take anything away from Bill But:
不要拿走Bill But的任何东西:
- I have never heard of him.
- He is a Geo-Physists not a computer programmer
- He recomends programming in Java to improve your C++
- The languages are now so different in usage that is utterly false).
- If you want to use references of What to-do/not to-do.
Then I would pick one of the Big names in the C++ field:
Stroustrup/Sutter/Alexandrescu/Meyers
他是地理医师,不是计算机程序员
他建议用Java编程来改进你的C ++
现在语言的使用方式如此不同,这是完全错误的。
如果您想使用什么做什么/不做什么的参考。然后我会选择C ++领域的一个大牌:Stroustrup / Sutter / Alexandrescu / Meyers
我从未听说过他。他是一名地理医师而不是计算机程序员他建议使用Java编程来改进你的C ++语言现在的使用方式如此不同,这是完全错误的。如果您想使用什么做什么/不做什么的参考。然后我会选择C ++领域的一个大牌:Stroustrup / Sutter / Alexandrescu / Meyers
Summary:
- Don't use RAW pointers (when ownership is required)
- Do use smart pointers.
- Don't copy objects into your object (it will slice).
- You can use references (but know the limitations).
不要使用RAW指针(需要所有权时)
使用智能指针。
不要将对象复制到对象中(它会切片)。
您可以使用引用(但知道限制)。
My example of Dependency injection using references:
class Lexer
{
public: Lexer(std::istream& input,std::ostream& errors);
... STUFF
private:
std::istream& m_input;
std::ostream& m_errors;
};
class Parser
{
public: Parser(Lexer& lexer);
..... STUFF
private:
Lexer& m_lexer;
};
int main()
{
CLexer lexer(std::cin,std::cout); // CLexer derived from Lexer
CParser parser(lexer); // CParser derived from Parser
parser.parse();
}
// In test.cpp
int main()
{
std::stringstream testData("XXXXXX");
std::stringstream output;
XLexer lexer(testData,output);
XParser parser(lexer);
parser.parse();
}
#2
4
Summary: If you need to store a reference, store a pointer as a private variable and access it through a method which dereferences it. You can stick a check that the pointer isn't null in the object's invariant.
简介:如果需要存储引用,请将指针存储为私有变量,并通过解除引用的方法访问它。您可以在对象的不变量中检查指针不为空。
In depth:
Firstly, storing references in classes makes it impossible to implement a sensible and legal copy constructor or assignment operator, so they should be avoided. It is usually a mistake to use one.
首先,在类中存储引用使得无法实现合理的合法拷贝构造函数或赋值运算符,因此应该避免使用它们。使用它通常是一个错误。
Secondly, the type of pointer/reference passed in to functions and constructors should indicate who has responsibility for freeing the object and how it should be freed:
其次,传递给函数和构造函数的指针/引用的类型应该指示谁有责任释放对象以及如何释放它:
-
std::auto_ptr - the called function has reposibility, and will do so automatically when it's done. If you need copy semantics, the interface must provide a clone method which should return an auto_ptr.
std :: auto_ptr - 被调用的函数具有可重用性,并在完成后自动执行。如果需要复制语义,接口必须提供一个克隆方法,该方法应返回auto_ptr。
-
std::shared_ptr - the called function has responsibility, and will do so automatically when it's done and when all other references to the object are gone. If you need shallow copy semantics the compiler generated functions will be fine, if you need deep copying the interface must provide a clone method which should return a shared_ptr.
std :: shared_ptr - 被调用的函数有责任,并且当它完成时以及对该对象的所有其他引用都消失时将自动执行。如果你需要浅拷贝语义,编译器生成的函数就可以了,如果需要深度复制,接口必须提供一个应该返回shared_ptr的克隆方法。
-
A reference - the caller has responsibility. You don't care - the object may be stack allocated for all you know. In this case you should pass by reference but store by pointer. If you need shallow copy semantics the compiler generated functions will be fine, if you need deep copying you're in trouble.
参考 - 来电者有责任。你不关心 - 对象可能是为你所知道的所有人分配的堆栈。在这种情况下,您应该通过引用传递,但按指针存储。如果你需要浅拷贝语义,那么编译器生成的函数就可以了,如果你需要深度复制就会遇到麻烦。
-
A raw pointer. Who knows? Could be allocated anywhere. Could be null. You might have repsibility for freeing it, you might not.
一个原始指针。谁知道?可以在任何地方分配。可以为null。你可能有可释放它的可行性,你可能没有。
-
Any other smart pointer - it should manage the lifetime for you, but you'll need to look at the you'll need to look at the documentation to see what the requirements are for copying.
任何其他智能指针 - 它应该为您管理生命周期,但您需要查看您需要查看文档以了解复制的要求。
Note that the methods which give you responsibility for freeing the object don't break DI - freeing the object is simply a part of the contract you have with the interface (as you don't need to know anything about the concrete type to free it).
请注意,让您负责释放对象的方法不会破坏DI - 释放对象只是您与接口签订的合同的一部分(因为您不需要了解具体类型的任何内容来释放它) )。
#3
1
I would steer clear of references as members since they tend to cause no end of headaches if you end up sticking one of your objects in an STL container. I would look into using a combination of boost::shared_ptr
for ownership and boost::weak_ptr
for dependents.
我会避免引用作为成员,因为如果你最终将一个对象粘贴在STL容器中,它们往往不会引起头痛。我会考虑将boost :: shared_ptr用于所有权,并将boost :: weak_ptr用于dependents。
#4
1
[update 1]
If you can always guarantee the dependency outlives the addict, you can use a raw pointer/reference, of course. between these two, I'd make a very simple decision: pointer if NULL is allowed, reference otherwise.
[更新1]如果您始终可以保证依赖性超过了上瘾者,那么您当然可以使用原始指针/引用。在这两者之间,我做了一个非常简单的决定:指针是否允许NULL,否则引用。
(The point of my original post was that neither pointer nor reference solve the lifetime problem)
(我原来的帖子的一点是既没有指针也没有引用解决了生命周期问题)
I'd follow the infamous google style guideline here, and use smart pointers.
我会遵循臭名昭着的谷歌风格指南,并使用智能指针。
Both a pointer and a reference have the same problem: you need to make sure the dependency outlives the addict. That pushes a quite nasty responsibility onto the client.
指针和引用都有同样的问题:你需要确保依赖性超过了上瘾者。这将一个非常讨厌的责任推到了客户身上。
With a (reference-counted) smart pointer, the policy becomes dependency is destroyed when noone uses it anymore. Sounds perfect to me.
使用(引用计数的)智能指针,当没有人再使用它时,策略变为依赖性被破坏。对我来说听起来很完美。
Even better: with boost::shared_ptr
(or a similar smart pointer that allows a type-neutral destruction policy) the policy is attached to the object at construction - which usually means everything affecting the dependency ends up in a single place.
更好的是:使用boost :: shared_ptr(或允许类型中立的销毁策略的类似智能指针),策略附加到构造对象 - 这通常意味着影响依赖的所有内容最终都在一个地方。
The typical problems of smart pointers - overhead and circular references - rarely come into play here. Dependency instances usually aren't tiny and numerous, and a dependency that has a strong reference back to its addicts is at least a code smell. (still, you need to keep these things in mind. Welcome back to C++)
智能指针的典型问题 - 开销和循环引用 - 在这里很少发挥作用。依赖实例通常不是很小而且数量众多,并且对其成瘾者有强烈参考的依赖性至少是代码味道。 (仍然,你需要记住这些事情。欢迎回到C ++)
Warning: I am not "totally sold" to DI, but I'm totally sold on smart pointers ;)
警告:我没有“完全卖掉”给DI,但我完全卖掉了智能指针;)
[update 2]
Note that you can always create a shared_ptr
to a stack/global instance using a null deleter.
This requires both sides to support this, though: addict must make guarantees that it will not transfer a reference to the dependency to someone else who might live longer, and caller is back with the responsibility ensuring lifetime. I am not to happy with this solution, but have used this on occasion.
[更新2]请注意,您始终可以使用空删除器为堆栈/全局实例创建shared_ptr。这需要双方支持这一点,但是:上瘾者必须保证不会将对依赖项的引用转移给可能活得更长的其他人,并且调用者回来负责确保生命周期。我对这个解决方案并不满意,但有时也会使用它。
#5
0
But then I get other, equally authoritive advices against using references as member : http://billharlan.com/pub/papers/Managing%5FCpp%5FObjects.html
但后来我得到了其他同样权威的建议,反对使用引用作为成员:http://billharlan.com/pub/papers/Managing%5FCpp%5FObjects.html
In this case I think you only want to set the object once, in the constructor, and never change it so no problem. But if you want to change it later on, use an init function, have a copy constructor, in short everything that would have to change the reference you will have to use pointers.
在这种情况下,我认为你只想在构造函数中设置一次对象,并且永远不要改变它,所以没问题。但是如果你想稍后改变它,使用init函数,有一个复制构造函数,简而言之,所有必须更改引用的东西都必须使用指针。
#6
0
It has been asked before, but my SO search skills are not up to finding it. To summarise my position - you should very rarely, if ever, use references as class members. Doing so causes all sorts of initialisation, assignment and copying problems. Instead, use a pointer or a value.
之前有人问过,但是我的SO搜索技巧还没有找到它。总结一下我的立场 - 你应该很少(如果有的话)使用引用作为类成员。这样做会导致各种初始化,分配和复制问题。而是使用指针或值。
Edit: Found one - this is a question with a variety of opinions as answers: Should I prefer pointers or references in member data?
编辑:找到一个 - 这是一个有各种意见的问题作为答案:我是否更喜欢成员数据中的指针或引用?
#7
0
I can here my downmoderation coming already, but I will say that there should be no reference members in a class FOR ANY REASO, EVER. Except if they are a simple constant value. The reasons for this are many, the second you start this you open up all the bad things in C++. See my blog if you really care.
我可以在这里进行我的降级调整,但是我会说在课堂上不应该有任何参考成员。除非它们是一个简单的常数值。原因很多,第二个你开始这个,你用C ++打开所有不好的东西。如果你真的在乎我的博客。
#1
7
There is no hard and fast rule:
As people have mentioned using references inside objects can cause copy problems (and it does) so it is not a panacea, but for certain situation it can be useful (that is why C++ gives us the option to do it all these different ways). But using RAW pointers is really not an option. If you are dynamically allocating objects then you should always be maintaining them with smart pointers and your object should also be using smart pointers.
没有严格的规则:正如人们提到的,在对象中使用引用会导致复制问题(并且它确实存在)因此它不是灵丹妙药,但对于某些情况它可能是有用的(这就是为什么C ++给我们提供选项做所有这些不同的方式)。但是使用RAW指针实际上不是一个选择。如果您正在动态分配对象,那么您应该始终使用智能指针维护它们,并且您的对象也应该使用智能指针。
For people who demand examples: Streams are always passed and stored as references (as they can't be copied).
对于需要示例的人:Streams总是作为引用传递和存储(因为它们无法复制)。
Some Comments on your code examples:
您的代码示例的一些评论:
Example one and two
Your first example with pointers. Is basically the same as the second example using references. The difference being that a reference can not be NULL. When you pass a reference the object is already alive and thus should have a lifespan greater than the object you are testing already (If it was created on the stack) so it should be safe to keep a reference. If you are dynamically creating pointers as dependencies I would consider using boost::shared_pointer or std::auto_ptr depending if ownership of the dependency is shared or not.
你的第一个指针示例。与使用引用的第二个示例基本相同。不同之处在于引用不能为NULL。当您传递引用时,该对象已经存活,因此其寿命应该大于您正在测试的对象(如果它是在堆栈上创建的),那么保留引用应该是安全的。如果您动态创建指针作为依赖项,我会考虑使用boost :: shared_pointer或std :: auto_ptr,具体取决于是否共享依赖项的所有权。
Example Three:
I don't see any great use for your third example. This is because you can not use polymorphic types (If you pass an object derived from Dependency it will be sliced during the copy operation). Thus the code may as well be inside Addict rather than a separate class.
我认为你的第三个例子并没有什么用处。这是因为您不能使用多态类型(如果您传递从Dependency派生的对象,它将在复制操作期间被切片)。因此代码也可以在Addict中,而不是单独的类。
Bill Harlen: (http://billharlan.com/pub/papers/Managing%5FCpp%5FObjects.html)
Not to take anything away from Bill But:
不要拿走Bill But的任何东西:
- I have never heard of him.
- He is a Geo-Physists not a computer programmer
- He recomends programming in Java to improve your C++
- The languages are now so different in usage that is utterly false).
- If you want to use references of What to-do/not to-do.
Then I would pick one of the Big names in the C++ field:
Stroustrup/Sutter/Alexandrescu/Meyers
他是地理医师,不是计算机程序员
他建议用Java编程来改进你的C ++
现在语言的使用方式如此不同,这是完全错误的。
如果您想使用什么做什么/不做什么的参考。然后我会选择C ++领域的一个大牌:Stroustrup / Sutter / Alexandrescu / Meyers
我从未听说过他。他是一名地理医师而不是计算机程序员他建议使用Java编程来改进你的C ++语言现在的使用方式如此不同,这是完全错误的。如果您想使用什么做什么/不做什么的参考。然后我会选择C ++领域的一个大牌:Stroustrup / Sutter / Alexandrescu / Meyers
Summary:
- Don't use RAW pointers (when ownership is required)
- Do use smart pointers.
- Don't copy objects into your object (it will slice).
- You can use references (but know the limitations).
不要使用RAW指针(需要所有权时)
使用智能指针。
不要将对象复制到对象中(它会切片)。
您可以使用引用(但知道限制)。
My example of Dependency injection using references:
class Lexer
{
public: Lexer(std::istream& input,std::ostream& errors);
... STUFF
private:
std::istream& m_input;
std::ostream& m_errors;
};
class Parser
{
public: Parser(Lexer& lexer);
..... STUFF
private:
Lexer& m_lexer;
};
int main()
{
CLexer lexer(std::cin,std::cout); // CLexer derived from Lexer
CParser parser(lexer); // CParser derived from Parser
parser.parse();
}
// In test.cpp
int main()
{
std::stringstream testData("XXXXXX");
std::stringstream output;
XLexer lexer(testData,output);
XParser parser(lexer);
parser.parse();
}
#2
4
Summary: If you need to store a reference, store a pointer as a private variable and access it through a method which dereferences it. You can stick a check that the pointer isn't null in the object's invariant.
简介:如果需要存储引用,请将指针存储为私有变量,并通过解除引用的方法访问它。您可以在对象的不变量中检查指针不为空。
In depth:
Firstly, storing references in classes makes it impossible to implement a sensible and legal copy constructor or assignment operator, so they should be avoided. It is usually a mistake to use one.
首先,在类中存储引用使得无法实现合理的合法拷贝构造函数或赋值运算符,因此应该避免使用它们。使用它通常是一个错误。
Secondly, the type of pointer/reference passed in to functions and constructors should indicate who has responsibility for freeing the object and how it should be freed:
其次,传递给函数和构造函数的指针/引用的类型应该指示谁有责任释放对象以及如何释放它:
-
std::auto_ptr - the called function has reposibility, and will do so automatically when it's done. If you need copy semantics, the interface must provide a clone method which should return an auto_ptr.
std :: auto_ptr - 被调用的函数具有可重用性,并在完成后自动执行。如果需要复制语义,接口必须提供一个克隆方法,该方法应返回auto_ptr。
-
std::shared_ptr - the called function has responsibility, and will do so automatically when it's done and when all other references to the object are gone. If you need shallow copy semantics the compiler generated functions will be fine, if you need deep copying the interface must provide a clone method which should return a shared_ptr.
std :: shared_ptr - 被调用的函数有责任,并且当它完成时以及对该对象的所有其他引用都消失时将自动执行。如果你需要浅拷贝语义,编译器生成的函数就可以了,如果需要深度复制,接口必须提供一个应该返回shared_ptr的克隆方法。
-
A reference - the caller has responsibility. You don't care - the object may be stack allocated for all you know. In this case you should pass by reference but store by pointer. If you need shallow copy semantics the compiler generated functions will be fine, if you need deep copying you're in trouble.
参考 - 来电者有责任。你不关心 - 对象可能是为你所知道的所有人分配的堆栈。在这种情况下,您应该通过引用传递,但按指针存储。如果你需要浅拷贝语义,那么编译器生成的函数就可以了,如果你需要深度复制就会遇到麻烦。
-
A raw pointer. Who knows? Could be allocated anywhere. Could be null. You might have repsibility for freeing it, you might not.
一个原始指针。谁知道?可以在任何地方分配。可以为null。你可能有可释放它的可行性,你可能没有。
-
Any other smart pointer - it should manage the lifetime for you, but you'll need to look at the you'll need to look at the documentation to see what the requirements are for copying.
任何其他智能指针 - 它应该为您管理生命周期,但您需要查看您需要查看文档以了解复制的要求。
Note that the methods which give you responsibility for freeing the object don't break DI - freeing the object is simply a part of the contract you have with the interface (as you don't need to know anything about the concrete type to free it).
请注意,让您负责释放对象的方法不会破坏DI - 释放对象只是您与接口签订的合同的一部分(因为您不需要了解具体类型的任何内容来释放它) )。
#3
1
I would steer clear of references as members since they tend to cause no end of headaches if you end up sticking one of your objects in an STL container. I would look into using a combination of boost::shared_ptr
for ownership and boost::weak_ptr
for dependents.
我会避免引用作为成员,因为如果你最终将一个对象粘贴在STL容器中,它们往往不会引起头痛。我会考虑将boost :: shared_ptr用于所有权,并将boost :: weak_ptr用于dependents。
#4
1
[update 1]
If you can always guarantee the dependency outlives the addict, you can use a raw pointer/reference, of course. between these two, I'd make a very simple decision: pointer if NULL is allowed, reference otherwise.
[更新1]如果您始终可以保证依赖性超过了上瘾者,那么您当然可以使用原始指针/引用。在这两者之间,我做了一个非常简单的决定:指针是否允许NULL,否则引用。
(The point of my original post was that neither pointer nor reference solve the lifetime problem)
(我原来的帖子的一点是既没有指针也没有引用解决了生命周期问题)
I'd follow the infamous google style guideline here, and use smart pointers.
我会遵循臭名昭着的谷歌风格指南,并使用智能指针。
Both a pointer and a reference have the same problem: you need to make sure the dependency outlives the addict. That pushes a quite nasty responsibility onto the client.
指针和引用都有同样的问题:你需要确保依赖性超过了上瘾者。这将一个非常讨厌的责任推到了客户身上。
With a (reference-counted) smart pointer, the policy becomes dependency is destroyed when noone uses it anymore. Sounds perfect to me.
使用(引用计数的)智能指针,当没有人再使用它时,策略变为依赖性被破坏。对我来说听起来很完美。
Even better: with boost::shared_ptr
(or a similar smart pointer that allows a type-neutral destruction policy) the policy is attached to the object at construction - which usually means everything affecting the dependency ends up in a single place.
更好的是:使用boost :: shared_ptr(或允许类型中立的销毁策略的类似智能指针),策略附加到构造对象 - 这通常意味着影响依赖的所有内容最终都在一个地方。
The typical problems of smart pointers - overhead and circular references - rarely come into play here. Dependency instances usually aren't tiny and numerous, and a dependency that has a strong reference back to its addicts is at least a code smell. (still, you need to keep these things in mind. Welcome back to C++)
智能指针的典型问题 - 开销和循环引用 - 在这里很少发挥作用。依赖实例通常不是很小而且数量众多,并且对其成瘾者有强烈参考的依赖性至少是代码味道。 (仍然,你需要记住这些事情。欢迎回到C ++)
Warning: I am not "totally sold" to DI, but I'm totally sold on smart pointers ;)
警告:我没有“完全卖掉”给DI,但我完全卖掉了智能指针;)
[update 2]
Note that you can always create a shared_ptr
to a stack/global instance using a null deleter.
This requires both sides to support this, though: addict must make guarantees that it will not transfer a reference to the dependency to someone else who might live longer, and caller is back with the responsibility ensuring lifetime. I am not to happy with this solution, but have used this on occasion.
[更新2]请注意,您始终可以使用空删除器为堆栈/全局实例创建shared_ptr。这需要双方支持这一点,但是:上瘾者必须保证不会将对依赖项的引用转移给可能活得更长的其他人,并且调用者回来负责确保生命周期。我对这个解决方案并不满意,但有时也会使用它。
#5
0
But then I get other, equally authoritive advices against using references as member : http://billharlan.com/pub/papers/Managing%5FCpp%5FObjects.html
但后来我得到了其他同样权威的建议,反对使用引用作为成员:http://billharlan.com/pub/papers/Managing%5FCpp%5FObjects.html
In this case I think you only want to set the object once, in the constructor, and never change it so no problem. But if you want to change it later on, use an init function, have a copy constructor, in short everything that would have to change the reference you will have to use pointers.
在这种情况下,我认为你只想在构造函数中设置一次对象,并且永远不要改变它,所以没问题。但是如果你想稍后改变它,使用init函数,有一个复制构造函数,简而言之,所有必须更改引用的东西都必须使用指针。
#6
0
It has been asked before, but my SO search skills are not up to finding it. To summarise my position - you should very rarely, if ever, use references as class members. Doing so causes all sorts of initialisation, assignment and copying problems. Instead, use a pointer or a value.
之前有人问过,但是我的SO搜索技巧还没有找到它。总结一下我的立场 - 你应该很少(如果有的话)使用引用作为类成员。这样做会导致各种初始化,分配和复制问题。而是使用指针或值。
Edit: Found one - this is a question with a variety of opinions as answers: Should I prefer pointers or references in member data?
编辑:找到一个 - 这是一个有各种意见的问题作为答案:我是否更喜欢成员数据中的指针或引用?
#7
0
I can here my downmoderation coming already, but I will say that there should be no reference members in a class FOR ANY REASO, EVER. Except if they are a simple constant value. The reasons for this are many, the second you start this you open up all the bad things in C++. See my blog if you really care.
我可以在这里进行我的降级调整,但是我会说在课堂上不应该有任何参考成员。除非它们是一个简单的常数值。原因很多,第二个你开始这个,你用C ++打开所有不好的东西。如果你真的在乎我的博客。