请考虑以下示例代码:
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()),我仍然可以调用放置构造函数.但是,如果我省略这一点,如上所述,并手动初始化每个成员变量,是否会导致未定义的行为?即绕过构造函数本身未定义的行为,或者用类外的一些等效代码替换调用它是否合法?
(通过另一个完全不同的问题遇到这个问题;要求好奇......)
标准对程序退出期间的函数局部静态初始化有什么看法?
编辑:为了清楚起见,我的意思是代码示例中的情况 - 本地静态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 更感兴趣,如果它在这个主题上有什么不同的话。
当心,我们正在绕过龙的巢穴.
考虑以下两个类:
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分三步构建:
为a分配原始存储空间 Foo
Base通过placement-new 初始化一个适当放置的子对象
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) 哪些代码有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) 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,我担心通过这样做导致"内存泄漏".
我在MEF的部件生命周期中遇到了一些问题,导致我的Prism应用程序中出现内存泄漏.
我的应用程序导出视图和视图模型,并将PartCreationPolicy其设置为CreationPolicy.NonShared.视图和视图模型分别继承ViewBase和ViewModelBase实现IDisposable.
现在,由于我的部件实现了IDisposable,因此容器会保留对它们的引用,这会导致它们不被垃圾收集器释放.根据MEF关于部件寿命的文档,这是设计的:
除非满足下列条件之一,否则容器将不会保留对其创建的零件的引用:
- 该部分标记为
Shared- 该部分实现
IDisposable- 一个或多个导入配置为允许重构
那怎么能让MEF不参考这些部分呢?是否有一个属性我可以用来让MEF知道我不希望它保留对我的部分的引用,即使它实现了IDisposable?
上述文章中讨论的两种策略对我来说似乎都不是很好的解决方案:
ReleaseExport需要一个Export对象作为参数,我不知道如何提供.我有我的观点的实例,但是我无法知道用于创建视图的合同是什么.如果有一个重载ReleaseExport可以接收容器创建的任何对象,那将会很棒.任何帮助将不胜感激.
我发现以下方案延长了临时工作的寿命,我不知道是否应该,但确实如此.
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的规则是否相同?
请让我开始,我知道从构造函数/析构函数中调用虚函数是一种不好的做法。然而,这样做的行为,虽然它可能令人困惑或不是用户所期望的,但仍然是明确定义的。
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) 在下面的简短示例中,关于指针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?似乎它可以拥有的唯一合理的可能值是指向对象的指针,这与该语句相矛盾。看到这个问题。
例如,我在服务工作者中声明一个全局变量,例如
var cacheVersion = "v1"; // line no 1 in sw.js
Run Code Online (Sandbox Code Playgroud)
这个变量的生命周期是多少?该变量是否会一直存在,直到 Service Worker 取消注册为止,或者如果 Service Worker 处于空闲状态,是否会删除该变量。
object-lifetime ×10
c++ ×7
malloc ×2
memory-leaks ×2
.net ×1
c# ×1
c++11 ×1
closures ×1
javascript ×1
lifetime ×1
mef ×1
prism ×1
static ×1