标签: object-lifetime

使用生命周期范围时如何处理运行时参数?

警告,提前很长时间.

我最近一直在思考这个问题,我很难在这里找到令人满意的解决方案.我将使用C#和autofac作为示例.

问题

IoC非常适合构建无状态服务的大型树.我解析服务并仅将数据传递给方法调用.大.

有时,我想将数据参数传递给服务的构造函数.这就是工厂的用途.而不是解析服务我解析它的工厂,并使用参数调用create方法来获取我的服务.多一点工作但还可以.

有时,我希望我的服务在一定范围内解析为同一个实例.Autofac提供了InstancePerLifeTimeScope()非常方便的功能.它允许我总是在执行子树中解析到同一个实例.好.

有时候我想要结合两种方法.我想在构造函数中的数据参数,并具有作用域的实例.我还没有找到一种令人满意的方法来实现这一目标.

解决方案

1.初始化方法

而不是将数据传递给构造函数,只需将其传递给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()之前,存在实例将被解析并在其他地方使用的危险.

2.持有人模式

这是一个包含对数据对象的引用的模式,而不是注入数据对象本身,我注入了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

31
推荐指数
1
解决办法
2246
查看次数

对象在C++中存在意味着什么?

[class.dtor]/15读取,强调我的:

一旦为对象调用析构函数,该对象就不再存在 ; 如果为生命周期结束的对象调用析构函数,则行为未定义(3.8).

但是,据我所知,这是标准中对"现有"对象的唯一引用.这似乎与[basic.life]形成鲜明对比,后者更具体:

类型对象的生命周期在以下情况T结束:

  • 如果T是具有非平凡析构函数(12.4)的类类型,则析构函数调用将启动,或者

  • 对象占用的存储器被重用或释放.

我们在这里有两个不同的措辞:"对象的生命周期结束"和"对象不再存在",前者只发生在一个非平凡的析构函数中,后者发生在任何析构函数中.差异的意义是什么?一个物体不再存在的含义是什么?

c++ object-lifetime language-lawyer c++11 c++14

30
推荐指数
1
解决办法
819
查看次数

是否可以通过const引用返回默认参数的值?

是否可以通过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

27
推荐指数
3
解决办法
662
查看次数

memcpy/memmove给工会成员,这是否设置了"活跃"成员?

重要的澄清:一些评论者似乎认为我是从工会复制的.仔细查看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)

c++ object-lifetime unions language-lawyer c++11

26
推荐指数
1
解决办法
1373
查看次数

关于将const引用绑定到临时的子对象

用代码就好

#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中的错误还是标准允许的内容?

c++ reference temporary object-lifetime language-lawyer

24
推荐指数
3
解决办法
1203
查看次数

在显式销毁对象之后但在其内存被释放之前调用成员函数是否合法?

我有这个代码:

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

23
推荐指数
2
解决办法
2507
查看次数

关于在构造函数中绑定临时成员的虚假警告

我理解如果临时绑定到构造函数的初始化列表中的引用成员,则该对象将在构造函数返回时被销毁.

但是,请考虑以下代码:

#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)

c++ g++ object-lifetime c++11

22
推荐指数
2
解决办法
1259
查看次数

做嵌套TRY/FINALLY语句的最佳实践

嗨,在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)

你能建议一个更好的方法吗?

delphi memory-management object-lifetime try-finally

20
推荐指数
2
解决办法
5323
查看次数

终身扩展和条件运算符

本地左值引用-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

20
推荐指数
1
解决办法
540
查看次数

为可变范围目的使用大括号是错误的吗?

我有时会使用大括号来隔离代码块,以避免以后错误地使用变量.例如,当我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)

c# scope coding-style stylecop object-lifetime

19
推荐指数
4
解决办法
2404
查看次数