C++中的内存管理优化
Memory management optimization in c++
我正在尝试实施一系列转换。表示变换前后的对象分别是 class A 和 class B 以最小化复杂度来演示示例。换句话说,class A 可以转换为 class B,class B 可以反向转换为 class A。此外,使用 [=56 的数据容器=] 在 class A 和 class B 的实现中被提取到 class Base 中。 Base class 如下图
class Base
{
public:
Base() // Default constructor
{
this->size = 0;
}
~Base()
{
}
Base(int input_size, float input_value) // Constructor
{
this->size = input_size;
this->data = std::make_unique<float[]>(input_size);
for (int loop_number = 0; loop_number < size; loop_number++) {
data[loop_number] = input_value;
}
}
std::unique_ptr<float[]> get_data()
{
// deep copy
auto return_data = std::make_unique<float[]>(size);
for (int loop_number = 0; loop_number < size; loop_number++) {
return_data[loop_number] = data[loop_number];
}
return return_data;
}
int get_size()
{
return this->size;
}
protected:
int size;
std::unique_ptr<float[]> data;
};
接下来,class A 和 class B 继承了 class Base。
class B;
class A : public Base
{
public:
A(int input_size, std::unique_ptr<int[]> const& input_data) // constructor
{
std::cout << "Object A " << std::to_address(this) << " constructed.\n"; // for observation
this->size = input_size;
this->data = std::make_unique<float[]>(this->size);
for (int loop_number = 0; loop_number < input_size; loop_number++)
{
this->data[loop_number] = input_data[loop_number]; // Deep copy
}
}
A& operator=(A const& InputImage) // Copy Assign
{
this->size = InputImage.size;
for (int loop_number = 0; loop_number < this->size; loop_number++)
{
this->data[loop_number] = InputImage.data[loop_number]; // Deep copy
}
return *this;
}
~A()
{
std::cout << "Object A " << std::to_address(this) << " destructed.\n"; // for observation
}
B to_B();
private:
int transform_to_B(int input_value)
{
return std::cos(input_value); // For example
}
};
class B : public Base
{
public:
B(int input_size, std::unique_ptr<int[]> const& input_data) // constructor
{
std::cout << "Object B " << std::to_address(this) << " constructed.\n"; // for observation
this->size = input_size;
this->data = std::make_unique<float[]>(this->size);
for (int loop_number = 0; loop_number < input_size; loop_number++)
{
this->data[loop_number] = input_data[loop_number]; // Deep copy
}
}
auto to_A()
{
std::unique_ptr<int[]> transformed_data = std::make_unique<int[]>(this->size);
for (int loop_number = 0; loop_number < this->size; loop_number++) {
transformed_data[loop_number] = transform_to_A(this->data[loop_number]);
}
return A(this->size, transformed_data);
}
~B()
{
std::cout << "Object B " << std::to_address(this) << " destructed.\n"; // for observation
}
private:
int transform_to_A(int input_value)
{
return std::acos(input_value); // For example
}
};
B A::to_B()
{
std::unique_ptr<int[]> transformed_data = std::make_unique<int[]>(this->size);
for (int loop_number = 0; loop_number < this->size; loop_number++) {
transformed_data[loop_number] = transform_to_B(this->data[loop_number]);
}
return B(this->size, transformed_data);
}
主要功能是测试classA和classB的转换结果。
int main()
{
const int size_for_testing = 3840 * 2160;
auto data_for_testing = std::make_unique<int[]>(size_for_testing);
for (int loop_number = 0; loop_number < size_for_testing; loop_number++) {
data_for_testing[loop_number] = 1; // for example
}
A a_object(size_for_testing, data_for_testing);
for (int loop_times = 0; loop_times < 1000; loop_times++) // for observation
{
// version 1
a_object = a_object.to_B().to_A().to_B().to_A().to_B().to_A();
}
return 0;
}
控制台输出为
Object A 00000038FC19FE28 constructed.
Object B 00000038FC19FE10 constructed.
Object A 00000038FC19FE00 constructed.
Object B 00000038FC19FDF0 constructed.
Object A 00000038FC19FDE0 constructed.
Object B 00000038FC19FDD0 constructed.
Object A 00000038FC19FDC0 constructed.
Object A 00000038FC19FDC0 destructed.
Object B 00000038FC19FDD0 destructed.
Object A 00000038FC19FDE0 destructed.
Object B 00000038FC19FDF0 destructed.
Object A 00000038FC19FE00 destructed.
Object B 00000038FC19FE10 destructed.
Object B 00000038FC19FE10 constructed.
Object A 00000038FC19FE00 constructed.
Object B 00000038FC19FDF0 constructed.
......
我知道为处理而创建的中期对象是 是有道理的。但是,如果出现更复杂的情况,比如a_object = a_object.to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A();
,保存这些中期对象可能会造成巨大的内存消耗。我很好奇设计的概念或哲学 "deallocating object at the end of the scope where it was declared"。也许可以根据使用情况进行优化。
另一方面,如下所示的单独表格的内存使用情况与版本1类似。
// version 2
auto temp1 = a_object.to_B();
auto temp2 = temp1.to_A();
auto temp3 = temp2.to_B();
auto temp4 = temp3.to_A();
auto temp5 = temp4.to_B();
a_object = temp5.to_A();
为了尽量减少内存消耗,Lambda表达式也考虑如下。但是,内存使用也和版本1差不多。
// version 3
auto temp1 = [](auto& input_object) { return input_object.to_B(); }(a_object);
auto temp2 = [](auto& input_object) { return input_object.to_A(); }(temp1);
auto temp3 = [](auto& input_object) { return input_object.to_B(); }(temp2);
auto temp4 = [](auto& input_object) { return input_object.to_A(); }(temp3);
auto temp5 = [](auto& input_object) { return input_object.to_B(); }(temp4);
auto a_object = [](auto& input_object) { return input_object.to_A(); }(temp5);
顺便说一句,这种Lambda表达式似乎不能像下面那样合并。编译器弹出C2664错误说'auto main::::operator ()(_T1 &) const': cannot convert argument 1 from 'B' to '_T1 &'
a_object = [](auto& input_object) { return input_object.to_A(); }(
[](auto& input_object) { return input_object.to_B(); }(
[](auto& input_object) { return input_object.to_A(); }(
[](auto& input_object) { return input_object.to_B(); }(
[](auto& input_object) { return input_object.to_A(); }(
[](auto& input_object) { return input_object.to_B(); }(a_object))))));
最后,我的问题是:
1) 我很好奇设计的概念或哲学"deallocating object at the end of the scope where it was declared"。也许可以根据使用情况进行优化。
2)有没有更好的方法来减少这种级联结构的内存消耗,比如
更复杂的情况 a_object = a_object.to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A();
?
环境:
CPU:英特尔®酷睿™ i7-6700HQ 2.6GHz
内存:16GB
OS: Windows 10 1909
IDE:Microsoft Visual Studio Community 2019 版本 16.4.5
1) I am curious that the concept or the philosophy of the designing "deallocating object at the end of the scope where it was declared". It maybe can be optimized based on the usage.
它允许"safety"使用临时语句。
假设规则可能允许在可观察到的行为相同之前解除分配。
哪个更复杂,因为你在析构函数中有输出。
2) Is there some better way to decrease the memory consumption to this kind of cascade structure such as the more complex case a_object = a_object.to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A();?
您可以为临时添加重载:
B A::to_B() &&
{
std::unique_ptr<int[]> transformed_data = std::make_unique<int[]>(this->size);
for (int loop_number = 0; loop_number < this->size; loop_number++) {
transformed_data[loop_number] = transform_to_B(this->data[loop_number]);
}
auto Bsize = this->size;
this->size = 0;
this->data.reset(); // We clear here.
// Implementation might even really transfer the buffer
return B(Bsize, std::move(transformed_data));
}
我正在尝试实施一系列转换。表示变换前后的对象分别是 class A 和 class B 以最小化复杂度来演示示例。换句话说,class A 可以转换为 class B,class B 可以反向转换为 class A。此外,使用 [=56 的数据容器=] 在 class A 和 class B 的实现中被提取到 class Base 中。 Base class 如下图
class Base
{
public:
Base() // Default constructor
{
this->size = 0;
}
~Base()
{
}
Base(int input_size, float input_value) // Constructor
{
this->size = input_size;
this->data = std::make_unique<float[]>(input_size);
for (int loop_number = 0; loop_number < size; loop_number++) {
data[loop_number] = input_value;
}
}
std::unique_ptr<float[]> get_data()
{
// deep copy
auto return_data = std::make_unique<float[]>(size);
for (int loop_number = 0; loop_number < size; loop_number++) {
return_data[loop_number] = data[loop_number];
}
return return_data;
}
int get_size()
{
return this->size;
}
protected:
int size;
std::unique_ptr<float[]> data;
};
接下来,class A 和 class B 继承了 class Base。
class B;
class A : public Base
{
public:
A(int input_size, std::unique_ptr<int[]> const& input_data) // constructor
{
std::cout << "Object A " << std::to_address(this) << " constructed.\n"; // for observation
this->size = input_size;
this->data = std::make_unique<float[]>(this->size);
for (int loop_number = 0; loop_number < input_size; loop_number++)
{
this->data[loop_number] = input_data[loop_number]; // Deep copy
}
}
A& operator=(A const& InputImage) // Copy Assign
{
this->size = InputImage.size;
for (int loop_number = 0; loop_number < this->size; loop_number++)
{
this->data[loop_number] = InputImage.data[loop_number]; // Deep copy
}
return *this;
}
~A()
{
std::cout << "Object A " << std::to_address(this) << " destructed.\n"; // for observation
}
B to_B();
private:
int transform_to_B(int input_value)
{
return std::cos(input_value); // For example
}
};
class B : public Base
{
public:
B(int input_size, std::unique_ptr<int[]> const& input_data) // constructor
{
std::cout << "Object B " << std::to_address(this) << " constructed.\n"; // for observation
this->size = input_size;
this->data = std::make_unique<float[]>(this->size);
for (int loop_number = 0; loop_number < input_size; loop_number++)
{
this->data[loop_number] = input_data[loop_number]; // Deep copy
}
}
auto to_A()
{
std::unique_ptr<int[]> transformed_data = std::make_unique<int[]>(this->size);
for (int loop_number = 0; loop_number < this->size; loop_number++) {
transformed_data[loop_number] = transform_to_A(this->data[loop_number]);
}
return A(this->size, transformed_data);
}
~B()
{
std::cout << "Object B " << std::to_address(this) << " destructed.\n"; // for observation
}
private:
int transform_to_A(int input_value)
{
return std::acos(input_value); // For example
}
};
B A::to_B()
{
std::unique_ptr<int[]> transformed_data = std::make_unique<int[]>(this->size);
for (int loop_number = 0; loop_number < this->size; loop_number++) {
transformed_data[loop_number] = transform_to_B(this->data[loop_number]);
}
return B(this->size, transformed_data);
}
主要功能是测试classA和classB的转换结果。
int main()
{
const int size_for_testing = 3840 * 2160;
auto data_for_testing = std::make_unique<int[]>(size_for_testing);
for (int loop_number = 0; loop_number < size_for_testing; loop_number++) {
data_for_testing[loop_number] = 1; // for example
}
A a_object(size_for_testing, data_for_testing);
for (int loop_times = 0; loop_times < 1000; loop_times++) // for observation
{
// version 1
a_object = a_object.to_B().to_A().to_B().to_A().to_B().to_A();
}
return 0;
}
控制台输出为
Object A 00000038FC19FE28 constructed.
Object B 00000038FC19FE10 constructed.
Object A 00000038FC19FE00 constructed.
Object B 00000038FC19FDF0 constructed.
Object A 00000038FC19FDE0 constructed.
Object B 00000038FC19FDD0 constructed.
Object A 00000038FC19FDC0 constructed.
Object A 00000038FC19FDC0 destructed.
Object B 00000038FC19FDD0 destructed.
Object A 00000038FC19FDE0 destructed.
Object B 00000038FC19FDF0 destructed.
Object A 00000038FC19FE00 destructed.
Object B 00000038FC19FE10 destructed.
Object B 00000038FC19FE10 constructed.
Object A 00000038FC19FE00 constructed.
Object B 00000038FC19FDF0 constructed.
......
我知道为处理而创建的中期对象是 a_object = a_object.to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A();
,保存这些中期对象可能会造成巨大的内存消耗。我很好奇设计的概念或哲学 "deallocating object at the end of the scope where it was declared"。也许可以根据使用情况进行优化。
另一方面,如下所示的单独表格的内存使用情况与版本1类似。
// version 2
auto temp1 = a_object.to_B();
auto temp2 = temp1.to_A();
auto temp3 = temp2.to_B();
auto temp4 = temp3.to_A();
auto temp5 = temp4.to_B();
a_object = temp5.to_A();
为了尽量减少内存消耗,Lambda表达式也考虑如下。但是,内存使用也和版本1差不多。
// version 3
auto temp1 = [](auto& input_object) { return input_object.to_B(); }(a_object);
auto temp2 = [](auto& input_object) { return input_object.to_A(); }(temp1);
auto temp3 = [](auto& input_object) { return input_object.to_B(); }(temp2);
auto temp4 = [](auto& input_object) { return input_object.to_A(); }(temp3);
auto temp5 = [](auto& input_object) { return input_object.to_B(); }(temp4);
auto a_object = [](auto& input_object) { return input_object.to_A(); }(temp5);
顺便说一句,这种Lambda表达式似乎不能像下面那样合并。编译器弹出C2664错误说'auto main::::operator ()(_T1 &) const': cannot convert argument 1 from 'B' to '_T1 &'
a_object = [](auto& input_object) { return input_object.to_A(); }(
[](auto& input_object) { return input_object.to_B(); }(
[](auto& input_object) { return input_object.to_A(); }(
[](auto& input_object) { return input_object.to_B(); }(
[](auto& input_object) { return input_object.to_A(); }(
[](auto& input_object) { return input_object.to_B(); }(a_object))))));
最后,我的问题是:
1) 我很好奇设计的概念或哲学"deallocating object at the end of the scope where it was declared"。也许可以根据使用情况进行优化。
2)有没有更好的方法来减少这种级联结构的内存消耗,比如
更复杂的情况 a_object = a_object.to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A();
?
环境:
CPU:英特尔®酷睿™ i7-6700HQ 2.6GHz
内存:16GB
OS: Windows 10 1909
IDE:Microsoft Visual Studio Community 2019 版本 16.4.5
1) I am curious that the concept or the philosophy of the designing "deallocating object at the end of the scope where it was declared". It maybe can be optimized based on the usage.
它允许"safety"使用临时语句。
假设规则可能允许在可观察到的行为相同之前解除分配。 哪个更复杂,因为你在析构函数中有输出。
2) Is there some better way to decrease the memory consumption to this kind of cascade structure such as the more complex case a_object = a_object.to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A().to_B().to_A();?
您可以为临时添加重载:
B A::to_B() &&
{
std::unique_ptr<int[]> transformed_data = std::make_unique<int[]>(this->size);
for (int loop_number = 0; loop_number < this->size; loop_number++) {
transformed_data[loop_number] = transform_to_B(this->data[loop_number]);
}
auto Bsize = this->size;
this->size = 0;
this->data.reset(); // We clear here.
// Implementation might even really transfer the buffer
return B(Bsize, std::move(transformed_data));
}