我的问题(在此之后,对于长篇介绍感到抱歉,问题在于粗体)最初的灵感来自于Herb Sutters Exceptional C++中的第23项,我们发现这样的内容:
<snip>
...
int main()
{
GenericTableAlgorithm a( "Customer", MyWorker() );
a.Process();
}
同
class GenericTableAlgorithm
{
public:
GenericTableAlgorithm( const string& table,
GTAClient& worker );
bool Process();
private:
struct GenericTableAlgorithmImpl* pimpl_; //implementation
};
class GTAClient
{
///...
virtual bool ProcessRow( const PrimaryKey& ) =0;
//...
};
class MyWorker : public GTAClient
{
// ... override Filter() and ProcessRow() to
// implement a specific operation ...
};
</剪断>
现在,我对该代码存在以下问题(不,我绝不怀疑Sutter先生作为C++专家的实力):
MyWorker …我是python的新手,并且一直在研究Swaroop CH的"A Byte of Python"中的示例.我看到一些__del__令我困惑的方法的行为.
基本上,如果我运行以下脚本(在Python 2.6.2中)
class Person4:
'''Represents a person'''
population = 0
def __init__(self, name):
'''Initialize the person's data'''
self.name = name
print 'Initializing %s'% self.name
#When the person is created they increase the population
Person4.population += 1
def __del__(self):
'''I am dying'''
print '%s says bye' % self.name
Person4.population -= 1
if Person4.population == 0:
print 'I am the last one'
else:
print 'There are still %d left' % Person4.population
swaroop = Person4('Swaroop')
kaleem …Run Code Online (Sandbox Code Playgroud) 为了阻止我最近给出的答案评论中的论点,我想对以下问题作一些建设性的答案:
Ben Voigt和简化示例代码(在ideone.com上运行):
#include <iostream>
#include <new>
struct something
{
int i;
};
int main(void)
{
char buffer[sizeof (something) + 40];
something* p = new (buffer) something;
p->i = 11;
int& outlives = p->i;
std::cout << outlives << "\n";
p->~something(); // p->i dies with its parent object
new (p) char[40]; // memory is reused, lifetime of *p (and p->i) is so done
new (&outlives) int(13);
std::cout << outlives << …Run Code Online (Sandbox Code Playgroud) 在派生类的析构函数执行之后但在基类的析构函数执行之前,C++标准对于对象状态的保证是什么?(这是派生类的子对象的析构函数被调用的时间.)
#include <string>
struct Base;
struct Member {
Member(Base *b);
~Member();
Base *b_;
};
struct Base {
virtual void f() {}
virtual ~Base() {}
};
struct Derived : Base {
Derived() : m(this) {}
virtual ~Derived() {}
virtual void f() {}
std::string s;
Member m;
};
Member::Member(Base *b) : b_(b) {}
Member::~Member() {
// At this point, ~Derived has finished -- can we use b_ as a
// Derived* object (i.e. call Derived::f or access Derived::s)?
b_->f();
} …Run Code Online (Sandbox Code Playgroud) 我将把一个非常普遍的情况提炼成一般形式.假设我正在构建一些关闭的库对象,执行一些异步工作,然后在完成时回调委托方法.现在,也有一些随意的说法,我不能使用ARC或块来进行回调.这是老式的.我们将此对象称为Worker.
现在说各种应用程序中还有其他几个类,除了公共接口之外,它们对工作程序一无所知.他们将工人用于自己的目的.我们将这些类称为消费者.
Say Worker使委托回调如下:
// "Private" method called internally when work is done.
- (void)somethingFinished
{
[self.delegate workerDidFinish];
[self someTask];
}
Run Code Online (Sandbox Code Playgroud)
并说一些特定的Consumer处理回调如下:
- (void)workerDidFinish
{
// Assume "worker" is a retain property to a Worker
// instance that we previously created and began working,
// and that it's also the sender of the message.
self.worker = nil;
// Other code...
}
Run Code Online (Sandbox Code Playgroud)
现在,如果没有其他任何东西保留该特定的Worker实例,我们就遇到了麻烦.Worker将被释放,然后控制将返回其-somethingFinished方法,然后它将发送-someTask到回收或垃圾内存,并可能崩溃.没有人公然违反任何内存管理规则.
我不是在这里要求技术解决方案.我知道几种选择.我想知道修复责任的负担是谁.作为组件设计者,我是否应该实现Worker的-somethingFinished方法,以便在方法的持续时间内扩展工作者的生命周期[[self retain] autorelease]?或者,作为组件的使用者,我是否应该知道我可能会在实例方法中途吹走一个对象,并等到稍后才释放它?
这个问题的答案似乎都表明从回调中释放对象是一个坏主意.不幸的是,在这个问题中有很多令人分心的信息,关于如何将Worker(这个实例中的CLLocationManager)传递给我在这里故意避免的委托.这个问题遇到了同样的情况,并提供了另一种解决方案.
就个人而言,我看不出消费者如何承担责任.它没有破坏任何内存管理规则,并且礼貌地消耗了Worker的公共接口.它只是在不再需要时释放一个实例.但另一方面,这是否意味着任何可能以某种方式在中间方法解除分配的对象需要人为地延长其自身的寿命?毕竟,委托方法不是消息发送方最终在方法中间解除分配的唯一方法.
最终,谁负责修复?工人?消费者?可以通过规范来确定吗?
在C++ 11标准的12.2中:
绑定引用的临时对象或绑定引用的子对象的完整对象的临时对象在引用的生命周期内持续存在,除了:
绑定到构造函数的ctor-initializer(12.6.2)中的引用成员的临时绑定将持续存在,直到构造函数退出.
函数调用(5.2.2)中的引用参数的临时绑定将持续到包含该调用的完整表达式完成为止.
函数返回语句(6.6.3)中返回值临时绑定的生命周期未扩展; 临时在return语句中的full-expression结束时被销毁.
在new-initializer(5.3.4)中对引用的临时绑定将持续到包含new-initializer的full-expression完成为止.
并且标准中有最后一个案例:
struct S {
int mi;
const std::pair<int,int>& mp;
};
S a { 1,{2,3} }; // No problem.
S* p = new S{ 1, {2,3} }; // Creates dangling reference
Run Code Online (Sandbox Code Playgroud)
对我而言,2. and 3.理解并容易达成一致.但是原因是1. and 4.什么?这个例子对我来说看起来很邪恶.
当我使用ElasticSearch.NET建立与ElasticSearch集群的连接时,我使用的代码块如下:
var uris = settingsProvider.ElasticSearchUri.Split(';').Select(x => new Uri(x));
var sniffingConnectionPool = new SniffingConnectionPool(uris);
var connectionConfiguration =
new ConnectionConfiguration(sniffingConnectionPool)
.SniffOnConnectionFault()
.SniffOnStartup();
var client = new ElasticsearchClient(settings: connectionConfiguration);
Run Code Online (Sandbox Code Playgroud)
难道建议我memoize的/让静态/做一个单包装的ElasticsearchClient,对ConnectionConfiguration,或者SniffingConnectionPool使他们不必每次都让我搜到重建?
众所周知(或应该)是结合的结果std::min的const参考是一个非常糟糕的主意,每当其中一个参数std::min是右值,因为const参考结合不是通过函数返回传播.所以下面的代码
#include <iostream>
#include <algorithm>
int main()
{
int n = 42;
const int& r = std::min(n - 1, n + 1); // r is dangling after this line
std::cout << r;
}
Run Code Online (Sandbox Code Playgroud)
应该产生未定义的行为,因为r悬空.事实上,当使用gcc5.2编译时使用-Wall -O3编译器吐出
警告:
<anonymous>在此函数中使用未初始化[-Wuninitialized]
但是,使用相同的标志(甚至包括)使用clang(llvm 7.0.0)进行编译时-Wextra不会发出任何警告,并且程序似乎"正常",即显示41.
问题:铿锵声使用的是"安全"版本std::min吗?就像一个版本,当一个参数是一个rvalue时,它使用一些SFINAE来按值返回?或者它是否根本不需要发出任何诊断并且程序"发生"以在此UB场景中产生"正确"结果?
如果我理解正确,从C++ 17开始,此代码现在要求不进行任何复制:
Foo myfunc(void) {
return Foo();
}
auto foo = myfunc(); // no copy
Run Code Online (Sandbox Code Playgroud)
函数参数也是如此吗?是否会在以下代码中优化副本?
Foo myfunc(Foo foo) {
return foo;
}
auto foo = myfunc(Foo()); // will there be copies?
Run Code Online (Sandbox Code Playgroud) 这段代码:
#include <iostream>
using namespace std;
int* fun()
{
int a = 5;
int* pointerA = &a;
cout << pointerA << endl;
return pointerA;
}
int main()
{
int* p = fun();
cout << p << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
打印以下内容:
0x[some address]
0
Run Code Online (Sandbox Code Playgroud)
我知道a函数fun()返回时会释放该变量,但是为什么cout << p << endl;返回0?即使变量在技术上不再存在,它也不应该指向内存中的相同地址吗?这是编译器功能还是未定义的行为?
编辑:我找到了罪魁祸首。我正在使用CodeBlocks,并且在该项目的构建选项中,有一个标志“优化更多(以提高速度)[-O2]”。如果选中,则得到0,如果不选中该标志,则得到相同的address 0x[some address],这是预期的行为。
对于没有提及我的IDE,我深表歉意。
c++ pointers object-lifetime undefined-behavior language-lawyer
object-lifetime ×10
c++ ×7
reference ×2
.net ×1
c++11 ×1
c++17 ×1
clang++ ×1
copy-elision ×1
del ×1
destructor ×1
libc++ ×1
objective-c ×1
pointers ×1
python ×1
temporary ×1