标签: object-lifetime

绕过一个类的构造函数是合法的还是会导致未定义的行为?

请考虑以下示例代码:

class C
{
public:
    int* x;
};

void f()
{
    C* c = static_cast<C*>(malloc(sizeof(C)));
    c->x = nullptr; // <-- here
}
Run Code Online (Sandbox Code Playgroud)

如果由于任何原因我不得不忍受未初始化的内存(当然,如果可能的话,我会打电话new C()),我仍然可以调用放置构造函数.但是,如果我省略这一点,如上所述,并手动初始化每个成员变量,是否会导致未定义的行为?即绕过构造函数本身未定义的行为,或者用类外的一些等效代码替换调用它是否合法?

(通过另一个完全不同的问题遇到这个问题;要求好奇......)

c++ malloc object-lifetime language-lawyer

15
推荐指数
2
解决办法
654
查看次数

程序退出期间的函数局部静态初始化

标准对程序退出期间的函数局部静态初始化有什么看法? 编辑:为了清楚起见,我的意思是代码示例中的情况 - 本地静态b是在构造另一个静态之后a构造的(因此应该b在之前销毁a),但b也在a的析构函数期间构造,所以它应该立即销毁吗?后?优?

我没有设法找到有关此事的任何参考资料。

我想知道这种情况是 UB,还是应该有一些定义的行为?

下面的代码就是一个例子:

struct B{};

void foo()
{
    static B b;
}

struct A
{
    ~A() { foo(); }
};

int main()
{
    static A a;
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如您所见,A 的析构函数会在程序退出时发生(因为它具有静态存储),并且它会尝试构造 B 静态实例。

我对 C++17 更感兴趣,如果它在这个主题上有什么不同的话。

c++ static object-lifetime language-lawyer

15
推荐指数
1
解决办法
209
查看次数

通过placement-new手动构建一个简单的基类

当心,我们正在绕过龙的巢穴.

考虑以下两个类:

struct Base {
    std::string const *str;
};

struct Foo : Base {
    Foo() { std::cout << *str << "\n"; }
};
Run Code Online (Sandbox Code Playgroud)

如您所见,我正在访问未初始化的指针.还是我?

让我们假设我只使用Base那些微不足道的类,只不过是(可能是嵌套的)指针.

static_assert(std::is_trivial<Base>{}, "!");
Run Code Online (Sandbox Code Playgroud)

我想Foo分三步构建:

  1. 为a分配原始存储空间 Foo

  2. Base通过placement-new 初始化一个适当放置的子对象

  3. Foo通过placement-new 构建.

我的实现如下:

std::unique_ptr<Foo> makeFooWithBase(std::string const &str) {

    static_assert(std::is_trivial<Base>{}, "!");

    // (1)
    auto storage = std::make_unique<
        std::aligned_storage_t<sizeof(Foo), alignof(Foo)>
    >();

    Foo * const object = reinterpret_cast<Foo *>(storage.get());
    Base * const base = object;

    // (2)
    new (base) Base{&str};

    // (3)
    new …
Run Code Online (Sandbox Code Playgroud)

c++ placement-new object-lifetime language-lawyer

13
推荐指数
1
解决办法
418
查看次数

使用new char []或malloc的结果来表示浮动*是UB(严格别名冲突)吗?

哪些代码有UB(具体来说,哪些违反了严格的别名规则)?

void a() {
    std::vector<char> v(sizeof(float));
    float *f = reinterpret_cast<float *>(v.data());
    *f = 42;
}

void b() {
    char *a = new char[sizeof(float)];
    float *f = reinterpret_cast<float *>(a);
    *f = 42;
}

void c() {
    char *a = new char[sizeof(float)];
    float *f = new(a) float;
    *f = 42;
}

void d() {
    char *a = (char*)malloc(sizeof(float));
    float *f = reinterpret_cast<float *>(a);
    *f = 42;
}

void e() {
    char *a = (char*)operator new(sizeof(float));
    float *f = reinterpret_cast<float *>(a);
    *f = …
Run Code Online (Sandbox Code Playgroud)

c++ malloc strict-aliasing object-lifetime language-lawyer

13
推荐指数
1
解决办法
481
查看次数

在匿名代表中捕获的私有字段

class A
{
   public event EventHandler AEvent;
}
class B
{
   private A _foo;
   private int _bar;

   public void AttachToAEvent()
   {
      _foo.AEvent += delegate()
      {
         ...
         UseBar(_bar);
         ...
      }
   }
} 
Run Code Online (Sandbox Code Playgroud)

由于delegate捕获变量this._bar,它是否隐含地保持实例B?将B通过事件处理程序和捕获的变量引用实例A吗?

如果_bar是方法的局部变量,它会有所不同AttachToAEvent吗?

因为在我的情况下,A生命的实例远远长于并且远小于实例B,我担心通过这样做导致"内存泄漏".

c# closures memory-leaks anonymous-methods object-lifetime

12
推荐指数
2
解决办法
1651
查看次数

MEF保留对NonShared IDisposable部件的引用,不允许GC收集它们

我在MEF的部件生命周期中遇到了一些问题,导致我的Prism应用程序中出现内存泄漏.

我的应用程序导出视图和视图模型,并将PartCreationPolicy其设置为CreationPolicy.NonShared.视图和视图模型分别继承ViewBaseViewModelBase实现IDisposable.

现在,由于我的部件实现了IDisposable,因此容器会保留对它们的引用,这会导致它们不被垃圾收集器释放.根据MEF关于部件寿命的文档,这是设计的:

除非满足下列条件之一,否则容器将不会保留对其创建的零件的引用:

  • 该部分标记为 Shared
  • 该部分实现 IDisposable
  • 一个或多个导入配置为允许重构

那怎么能让MEF不参考这些部分呢?是否有一个属性我可以用来让MEF知道我不希望它保留对我的部分的引用,即使它实现了IDisposable

上述文章中讨论的两种策略对我来说似乎都不是很好的解决方案:

  • ReleaseExport需要一个Export对象作为参数,我不知道如何提供.我有我的观点的实例,但是我无法知道用于创建视图的合同是什么.如果有一个重载ReleaseExport可以接收容器创建的任何对象,那将会很棒.
  • 使用子容器似乎也不是一个自然的选择.

任何帮助将不胜感激.

.net memory-leaks prism mef object-lifetime

12
推荐指数
2
解决办法
7021
查看次数

通过rvalue数据成员延长临时生命周期与聚合一起使用,但不使用构造函数,为什么?

我发现以下方案延长了临时工作的寿命,我不知道是否应该,但确实如此.

struct S {
    std::vector<int>&& vec;
};

int main() {
    S s1{std::vector<int>(5)};      // construct with temporary
    std::cout << s1.vec[0] << '\n'; // fine, temporary is alive
}
Run Code Online (Sandbox Code Playgroud)

但是,当S给定显式值构造函数时,它不再是聚合,并且此方案失败并且读取无效s1.vec[0]

struct S {
    std::vector<int>&& vec;
    S(std::vector<int>&& v)
        : vec{std::move(v)}         // bind to the temporary provided
    { }
};

int main() {
    S s1{std::vector<int>(5)};      // construct with temporary
    std::cout << s1.vec[0] << '\n'; // not ok. invalid read on free'd memory
}
Run Code Online (Sandbox Code Playgroud)

为什么这对聚合有效?我认为它与构造函数是一个实际的函数调用有关,基于我使用const lvalue refs的红色.另外,有没有办法让后一种情况起作用?

在SO上使用左值引用处理类似情况有很多问题.我看到如果我使用了const lvalue ref,那么延长临时值的生命周期就无济于事了,rvalue refs的规则是否相同?

c++ object-lifetime rvalue-reference language-lawyer c++11

12
推荐指数
1
解决办法
663
查看次数

虚拟表创建线程安全吗?

请让我开始,我知道从构造函数/析构函数中调用虚函数是一种不好的做法。然而,这样做的行为,虽然它可能令人困惑或不是用户所期望的,但仍然是明确定义的。

struct Base
{
    Base()
    {
        Foo();
    }
    virtual ~Base() = default;
    virtual void Foo() const
    {
        std::cout << "Base" << std::endl;
    }
};

struct Derived : public Base
{
    virtual void Foo() const
    {
        std::cout << "Derived" << std::endl;
    }
};

int main(int argc, char** argv) 
{
    Base base;
    Derived derived;
    return 0;
}

Output:
Base
Base
Run Code Online (Sandbox Code Playgroud)

现在,回到我真正的问题。如果用户从不同线程的构造函数中调用虚函数会发生什么。有竞争条件吗?它是未定义的吗?或者换句话说。编译器设置 vtable 是线程安全的吗?

例子:

struct Base
{
    Base() :
        future_(std::async(std::launch::async, [this] { Foo(); }))
    {
    }
    virtual ~Base() = default;

    virtual void …
Run Code Online (Sandbox Code Playgroud)

c++ race-condition object-lifetime language-lawyer

12
推荐指数
1
解决办法
422
查看次数

对象生命周期结束和它何时不复存在之间有什么关系?

在下面的简短示例中,关于指针f指向或用于在从 返回之前指向的对象可以说些什么main

#include <vector>

struct foo {
    std::vector<int> m;
};

int main()
{
    auto f = new foo;
    f->~foo();
}
Run Code Online (Sandbox Code Playgroud)

我相信,不再是一个对象foo,其中f用于点。我收到了很多评论,说这可能不正确,而且可能有一个对象foo处于销毁、死亡或其他无效状态。

对于显式销毁但其存储仍然有效的对象的存在,语言标准有什么说法?

换句话说,是否可以合理地说仍然存在一个f超出其生命周期的对象?有没有一个对象不在它的生命周期中,没有开始构造并且没有被破坏?


编辑 :

很明显,一个对象可以在它不在其生命周期内时存在。在构造和销毁过程中,有一个对象,它的生命周期尚未开始或已经结束。来自https://timsong-cpp.github.io/cppwp/intro.object#1

[...] 一个对象在其构建期间 ([class.cdtor])、整个生命周期和销毁期间 ([class.cdtor]) 占用一个存储区域。[...]

但是在f->~foo();f(我们称之为o)指向的对象没有被构造之后,它不在它的生命周期中,也没有被破坏。我对本节的阅读是o不能再占用存储空间,因为它不在任何列举的情况下。似乎这意味着o不再有并且不再有指向的指针o。相反,如果您有一个指向o该指针的指针,那么该指针将指向o无法占用的存储空间。


编辑2:

如果不再有对象,那么还有什么样的价值foo?似乎它可以拥有的唯一合理的可能值是指向对象的指针,这与该语句相矛盾。看到这个问题

c++ lifetime object-lifetime language-lawyer

12
推荐指数
1
解决办法
364
查看次数

存储在 Service Worker 中的变量的生命周期是多少?

例如,我在服务工作者中声明一个全局变量,例如

var cacheVersion  = "v1"; // line no 1 in sw.js
Run Code Online (Sandbox Code Playgroud)

这个变量的生命周期是多少?该变量是否会一直存在,直到 Service Worker 取消注册为止,或者如果 Service Worker 处于空闲状态,是否会删除该变量。

javascript object-lifetime service-worker

12
推荐指数
2
解决办法
3506
查看次数