警告,提前很长时间.
我最近一直在思考这个问题,我很难在这里找到令人满意的解决方案.我将使用C#和autofac作为示例.
IoC非常适合构建无状态服务的大型树.我解析服务并仅将数据传递给方法调用.大.
有时,我想将数据参数传递给服务的构造函数.这就是工厂的用途.而不是解析服务我解析它的工厂,并使用参数调用create方法来获取我的服务.多一点工作但还可以.
有时,我希望我的服务在一定范围内解析为同一个实例.Autofac提供了InstancePerLifeTimeScope()非常方便的功能.它允许我总是在执行子树中解析到同一个实例.好.
有时候我想要结合两种方法.我想在构造函数中的数据参数,并具有作用域的实例.我还没有找到一种令人满意的方法来实现这一目标.
而不是将数据传递给构造函数,只需将其传递给Initialize方法.
接口:
interface IMyService
{
void Initialize(Data data);
void DoStuff();
}
Run Code Online (Sandbox Code Playgroud)
类:
class MyService : IMyService
{
private Data mData;
public void Initialize(Data data)
{
mData = data;
}
public void DoStuff()
{
//...
}
}
Run Code Online (Sandbox Code Playgroud)
注册:
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
Run Code Online (Sandbox Code Playgroud)
用法:
var myService = context.Resolve<IMyService>();
myService.Init(data);
// somewhere else
var myService = context.Resolve<IMyService>();
Run Code Online (Sandbox Code Playgroud)
在第一次解析服务并调用Initialize后,我可以愉快地在同一个上下文中解析并获得相同的初始化实例.我不喜欢在调用之前Initialize我有一个无法使用的对象的事实.在调用Initialize()之前,存在实例将被解析并在其他地方使用的危险.
这是一个包含对数据对象的引用的模式,而不是注入数据对象本身,我注入了holder对象.
接口:
interface IMyService
{
void DoStuff();
}
Run Code Online (Sandbox Code Playgroud)
类:
class MyService : …Run Code Online (Sandbox Code Playgroud) c# dependency-injection inversion-of-control autofac object-lifetime
[class.dtor]/15读取,强调我的:
一旦为对象调用析构函数,该对象就不再存在 ; 如果为生命周期结束的对象调用析构函数,则行为未定义(3.8).
但是,据我所知,这是标准中对"现有"对象的唯一引用.这似乎与[basic.life]形成鲜明对比,后者更具体:
类型对象的生命周期在以下情况
T结束:
如果
T是具有非平凡析构函数(12.4)的类类型,则析构函数调用将启动,或者对象占用的存储器被重用或释放.
我们在这里有两个不同的措辞:"对象的生命周期结束"和"对象不再存在",前者只发生在一个非平凡的析构函数中,后者发生在任何析构函数中.差异的意义是什么?一个物体不再存在的含义是什么?
是否可以通过const引用返回默认参数的值,如以下示例所示:
https://coliru.stacked-crooked.com/a/ff76e060a007723b
#include <string>
const std::string& foo(const std::string& s = std::string(""))
{
return s;
}
int main()
{
const std::string& s1 = foo();
std::string s2 = foo();
const std::string& s3 = foo("s");
std::string s4 = foo("s");
}
Run Code Online (Sandbox Code Playgroud) c++ object-lifetime language-lawyer default-arguments reference-binding
重要的澄清:一些评论者似乎认为我是从工会复制的.仔细查看memcpy,它从一个普通旧的地址复制uint32_t,它不包含在一个联合中.此外,我正在(通过memcpy)复制到一个联盟的特定成员(u.a16或者&u.x_in_a_union,不是直接复制到整个联盟本身(&u)
C++对工会非常严格 - 只有在成员写入的最后一个成员时才应该从成员中读取:
9.5 Unions [class.union] [[c ++ 11]]在一个联合中,最多一个非静态数据成员可以随时处于活动状态,即最多一个非静态的值数据成员可以随时存储在联合中.
(当然,编译器不会跟踪哪个成员是活动的.由开发人员来确保他们自己跟踪它)
更新:以下代码块是主要问题,直接反映问题标题中的文本.如果这段代码没问题,我会对其他类型进行跟进,但我现在意识到第一块代码本身很有趣.
#include <cstdint>
uint32_t x = 0x12345678;
union {
double whatever;
uint32_t x_in_a_union; // same type as x
} u;
u.whatever = 3.14;
u.x_in_a_union = x; // surely this is OK, despite involving the inactive member?
std::cout << u.x_in_a_union;
u.whatever = 3.14; // make the double 'active' again
memcpy(&u.x_in_a_union, &x); // same types, so should be …Run Code Online (Sandbox Code Playgroud) 用代码就好
#include <iostream>
struct P {
int x;
P(int x) : x(x) {}
~P() { std::cout << "~P()\n"; }
};
int main() {
auto const& x = P{10}.x;
std::cout << "extract\n";
}
Run Code Online (Sandbox Code Playgroud)
GCC打印~P() extract,表示临时的生命周期未被引用扩展.
相比之下,Clang(IMO正确)将临时的生命周期延长到引用的生命周期,x因此析构函数将在输出后调用main.
请注意,如果我们int使用某种类型(例如string),GCC会突然显示Clang的行为.
这是GCC中的错误还是标准允许的内容?
我有这个代码:
struct data {
void doNothing() {}
};
int main() {
data* ptr = new data();
ptr->~data();
ptr->doNothing();
::operator delete(ptr);
}
Run Code Online (Sandbox Code Playgroud)
请注意,doNothing()在对象被销毁之后但在其内存被释放之前被调用.看起来"对象生命周期"已经结束,但指针仍然指向正确分配的内存.成员函数不访问任何成员变量.
在这种情况下,成员函数调用是否合法?
c++ destructor object-lifetime language-lawyer explicit-destructor-call
我理解如果临时绑定到构造函数的初始化列表中的引用成员,则该对象将在构造函数返回时被销毁.
但是,请考虑以下代码:
#include <functional>
#include <iostream>
using callback_func = std::function<int(void)>;
int
func(const callback_func& callback)
{
struct wrapper
{
const callback_func& w_cb;
wrapper(const callback_func& cb) : w_cb {cb} { }
int call() { return this->w_cb() + this->w_cb(); }
};
wrapper wrp {callback};
return wrp.call();
}
int
main()
{
std::cout << func([](){ return 21; }) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这看起来对我来说完全有效.该callback对象将在整个func函数执行期间生效,并且不应为其wrapper构造函数创建临时副本.
实际上,GCC 4.9.0在启用所有警告的情况下编译正常.
但是,GCC 4.8.2编译器给了我以下警告:
$ g++ -std=c++11 -W …Run Code Online (Sandbox Code Playgroud) 嗨,在delphi中执行嵌套try和finally语句的最佳方法是什么?
var cds1 : TClientDataSet;
cds2 : TClientDataSet;
cds3 : TClientDataSet;
cds4 : TClientDataSet;
begin
cds1 := TClientDataSet.Create(application );
try
cds2 := TClientDataSet.Create(application );
try
cds3 := TClientDataSet.Create(application );
try
cds4 := TClientDataSet.Create(application );
try
///////////////////////////////////////////////////////////////////////
/// DO WHAT NEEDS TO BE DONE
///////////////////////////////////////////////////////////////////////
finally
cds4.free;
end;
finally
cds3.free;
end;
finally
cds2.free;
end;
finally
cds1.free;
end;
end;
Run Code Online (Sandbox Code Playgroud)
你能建议一个更好的方法吗?
本地左值引用-const和rvalue引用可以延长临时值的生命周期:
const std::string& a = std::string("hello");
std::string&& b = std::string("world");
Run Code Online (Sandbox Code Playgroud)
当初始值设定项不是简单表达式,但使用条件运算符时,这是否也有效?
std::string&& c = condition ? std::string("hello") : std::string("world");
Run Code Online (Sandbox Code Playgroud)
如果其中一个结果是临时对象,但另一个结果不是?
std::string d = "hello";
const std::string& e = condition ? d : std::string("world");
Run Code Online (Sandbox Code Playgroud)
当条件为假时,C++是否要求临时扩展的生命周期?
回答有关不可复制对象的问题时出现了这个问题.
c++ object-lifetime rvalue-reference temporary-objects c++11
我有时会使用大括号来隔离代码块,以避免以后错误地使用变量.例如,当我SqlCommand在同一个方法中放入几个s时,我经常复制粘贴代码块,最后混合名称并执行两次命令.添加大括号有助于避免这种情况,因为SqlCommand在错误的位置使用错误将导致错误.这是一个例子:
Collection<string> existingCategories = new Collection<string>();
// Here a beginning of a block
{
SqlCommand getCategories = new SqlCommand("select Title from Movie.Category where SourceId = @sourceId", sqlConnection, sqlTransaction);
getCategories.Parameters.AddWithValue("@sourceId", sourceId);
using (SqlDataReader categoriesReader = getCategories.ExecuteReader(System.Data.CommandBehavior.SingleResult))
{
while (categoriesReader.Read())
{
existingCategories.Add(categoriesReader["Title"].ToString());
}
}
}
if (!existingCategories.Contains(newCategory))
{
SqlCommand addCategory = new SqlCommand("insert into Movie.Category (SourceId, Title) values (@sourceId, @title)", sqlConnection, sqlTransaction);
// Now try to make a mistake and write/copy-paste getCategories instead of addCategory. It will not …Run Code Online (Sandbox Code Playgroud) object-lifetime ×10
c++ ×7
c++11 ×4
c# ×2
autofac ×1
c++14 ×1
coding-style ×1
delphi ×1
destructor ×1
g++ ×1
reference ×1
scope ×1
stylecop ×1
temporary ×1
try-finally ×1
unions ×1