gpt4 book ai didi

c++ - 声明析构函数会影响对象的生命周期吗?

转载 作者:搜寻专家 更新时间:2023-10-31 01:28:14 24 4
gpt4 key购买 nike

15 年后回到 C++ 并尝试使用“发现现代 C++”一书中描述的表达式模板概念,我遇到了一个我无法解释的行为(尽管我的 C++ 知识当时非常基础,所以我希望这是显而易见的)。

这是最小的例子(我知道它很长,但这是我能做的最好的说明问题):

#include <iostream>
#include <iomanip>

template <typename T>
class container {
private:
T data;

template<typename Src>
void copy_from(Src& that) {
data = that.get();
}

public:

using value_type = T;

inline T get() const {
auto p= data;
return p;
}

void set(T v) {
data = v;
}

template<typename Src>
container& operator=(const Src& that) {
copy_from(that);
return *this;
}

template<typename Src>
container(const Src& that){
copy_from(that);
}

container() = default;

friend std::ostream& operator <<(std::ostream& s, container<T> const & matrix) {
s << std::endl << std::fixed << std::setprecision(8) << matrix.data <<std::endl;
return s;
}
};

template <typename A1, typename A2>
class sum {
using mytype = sum<A1, A2>;
public:
sum(const A1 & a1, const A2 & a2):
a1(a1), a2(a2) {
std::cout <<"constructing sum ("<<(long)this<<") with a1 = " << (long)&a1 << " and a2 = " <<(long)&a2 << std::endl;
}

// (1)
// ~sum() {}

using value_type = std::common_type_t <typename A1::value_type, typename A2::value_type>;

inline value_type get() const {
std::cout <<"getting elem from sum ("<<(long)this<<") with a1 = " << (long)&a1 << " and a2 = " <<(long)&a2 << std::endl;

auto x = a1.get();
auto y = a2.get();
auto p = x + y;
return p;
}

void print() {
std::cout <<"I'm a sum ("<<(long)this<<") with a1 = " << (long)&a1 << " and a2 = " <<(long)&a2 << std::endl;
}

private:
const A1 &a1;
const A2 &a2;
};

template <typename A1, typename A2>
sum<A1, A2> inline operator+ (const A1& a1, const A2& a2) {
return {a1, a2};
}

template <typename A>
class apply {

public:
using value_type = typename A::value_type;
using function_type = std::function<value_type(value_type)>;

apply (const A& a, const function_type & f):
a(a), f(f) {std::cout <<"constructing apply ("<<(long)this<<") with a = " << (long)&a<< std::endl; }

inline value_type get() const {
std::cout <<"address of apply's member obj is " << (long)&a << ", type is " <<typeid(a).name() << std::endl;
auto p = f(a.get());
return p;
}

private:
const A &a;
const function_type & f;
};

template<typename T>
class applicator {
public:

using value_type = T;
using function_type = std::function<value_type(value_type)>;

applicator( const function_type & f): f(f) { }

template<typename A>
// (2)
inline apply<A> operator() (A param) {
std::cout <<"address of () param is " << (long)&param << ", type is " <<typeid(param).name() <<": ";
param.print();
apply<A> op { param, f };
return op;
}

private:
const function_type & f;
};

double square(double x) {
return x*x;
}

int main() {

std::cout << "--- Creating variable" << std::endl;
container<double> W;
std::cout << W;

std::cout << "--- Setting values in the variable" << std::endl;
W.set(4);

std::function<double(double)> my_fun = square;
applicator sq { my_fun };

std::cout << "decltype(W) is_trivially_copyable? " << std::is_trivially_copyable_v<decltype(W)> << std::endl;
std::cout << "decltype(W+W) is_trivially_copyable? " << std::is_trivially_copyable_v<decltype(W+W)> << std::endl;
std::cout << "decltype(sq(W+W)) is_trivially_copyable? " << std::is_trivially_copyable_v<decltype(sq(W+W))> << std::endl;

std::cout << "--- Performing function on addition" << std::endl;
std::cout << std::hex;

auto r = sq(W+W);

std::cout << "Created var r with address " <<(long)&r<<", type: " <<typeid(r).name() <<std::endl;

std::cout << "--- Copying to container and printing out results" << std::endl;
std::cout << r << std::endl;

return 0;
}

这是输出:

--- Creating variable

0.00000000
--- Setting values in the variable
decltype(W) is_trivially_copyable? 1
decltype(W+W) is_trivially_copyable? 1
decltype(sq(W+W)) is_trivially_copyable? 1
--- Performing function on addition
constructing sum (7ffeefbff3a0) with a1 = 7ffeefbff508 and a2 = 7ffeefbff508
address of () param is 7ffeefbff388, type is 3sumI9containerIdES1_E: I'm a sum (7ffeefbff388) with a1 = 7ffeefbff508 and a2 = 7ffeefbff508
constructing apply (7ffeefbff398) with a = 7ffeefbff388
Created var r with address 7ffeefbff4e0, type: 5applyI3sumI9containerIdES2_EE
--- Copying to container and printing out results
address of apply's member obj is 7ffeefbff388, type is 3sumI9containerIdES1_E
getting elem from sum (7ffeefbff388) with a1 = 7ffeefbff4c8 and a2 = 7ffeefbff3b0

0.00000000

// (2)中的参数按值传递,因此临时对象在 operator() 时被销毁存在,所以 a apply的成员类引用垃圾。这对我来说很有意义。但是如果我们取消注释类 sum 中的析构函数定义(参见 // (1) ),那么结果是正确的,最终的 sum对象引用正确 container秒。为什么?

如果我们将析构函数注释掉并更改 // (2)通过引用传递,一切似乎都正常工作。是因为 const 引用延长了 operator+ 返回的临时对象的生命周期吗? ?如果是这样,为什么 apply<A>构造函数不会延长 param 的生命周期来自 operator() 的对象? apply 类保留对构造函数中传递的对象的引用。

最佳答案

The parameter in // (2) is passed by value, so the temporary object gets destroyed when operator() exists and so the a member of apply class references garbage. That makes sense to me.

正确。在

inline apply<A> operator() (A param)

返回的apply<A>引用了 param它已经超出范围,所以你有一个悬空引用并且使用它是未定义的行为。

But if we uncomment the destructor definition from class sum (see // (1)), then the result is correct and the final sum object references correct containers. Why?

同样,未定义的行为。仅仅因为代码不应该工作并不意味着它不能。由于您有未定义的行为,它甚至可以为您提供“正确”的结果。

if we keep the destructor commented out and change // (2) to passing by reference, everything seems to work correctly. Is it because const reference extends the lifetime of the temporary object returned by operator+?

这是因为您已经绑定(bind)了对来自调用站点的对象的引用。这意味着当函数返回到调用点时,它所拥有的引用仍然指向您传递给它的有效对象。这意味着您的引用仍然指向一个有效的对象,并且您已经定义了行为。

If so, why apply<A> constructor does not extend the lifetime of the param object from operator()? The apply class keeps reference to the object passed in the constructor.

A const &仅延长局部临时函数的生命周期。

{ // start of some scope
const int& foo = function_that_returns_temporary();
} // end of some scope

以上是合法的,编译器会将返回值的生命周期延长到作用域的末尾。拥有

struct Foo
{
const int& bar
Foo(const int& ref) : bar(ref)
};

不延长什么的生命周期ref指的是。如果有的话ref指的是在 Foo 之前超出范围用它创建的对象被销毁,然后该对象留下一个悬空引用。

关于c++ - 声明析构函数会影响对象的生命周期吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52595300/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com