我对对象分配有一种奇怪的行为。如果你能解释为什么这个任务会像这样工作,我将非常感激。这花了我很多时间。 我正在使用Visual Studio Enterprise 2017(所有默认设置)。
代码:
def click():
entered_text = entry.get()
if len(entered_text) < 9:
output.delete(0.0, END)
output.insert(END, 'This is too short') #Click function
elif entered_text in pass_Type:
strength = pass_Type[entered_text]
output.delete(0.0, END)
output.insert(END, strength)
elif strength and len(entered_text) < 9: }
output.delete(0.0, END) }
output.insert(END, strength) } #What I entered
else:
output.delete(0.0, END)
output.insert(END, "This password is acceptable!") #When the password is ok
输出(最高为cin):
#include "stdafx.h"
#include <iostream>
using namespace std;
class Test
{
public:
Test()
{
cout << "Constructor of " << this << endl;
}
~Test()
{
cout << "Destructor of " << this << endl;
}
};
int main()
{
cout << "Assignment 1" << endl;
auto t = Test();
cout << "Assignment 2" << endl;
t = Test();
int i = 0;
cin >> i;
return 0;
}
预期输出(最高为cin):
Assignment 1
Constructor of 006FFC9F
Assignment 2
Constructor of 006FFBC7
Destructor of 006FFBC7
我想编写一个测试函数,它创建我的(模板)类的对象,进行一些测试,然后创建一个新对象并进行更多测试。问题是t在第二次赋值后保存已经被破坏的对象。 我知道我可以使用动态分配导致预期的行为,但为什么这个程序表现不同?
非常感谢你。 问候。
PS:结果是相同的,与Release / Debug或64/32位编译无关
编辑:更详细的例子:
Assignment 1
Constructor of 006FFC9F
Assignment 2
Destructor of 006FFC9F
Constructor of 006FFBC7
输出(它在末尾保存一个删除的指针!!!):
#include "stdafx.h"
#include <iostream>
using namespace std;
class Test
{
private:
float* val;
public:
Test()
{
val = new float;
cout << "Constructor of " << this << ", addr. of val: " << val << endl;
}
~Test()
{
cout << "Destructor of " << this << ", addr. of val: " << val << " --> DELETING VAL!" << endl;
delete val;
}
float* getVal() { return this->val; }
};
int main()
{
cout << "Assignment 1" << endl;
auto t = Test();
cout << "Assignment 2" << endl;
t = Test();
cout << "Val Address: " << t.getVal() << endl;
int i = 0;
cin >> i;
return 0;
}
答案 0 :(得分:3)
使用
auto t = Test();
您实际上构建了两个对象。首先是构造临时对象的Test()
。第二个是t
的构造,它是通过 copy-construction 制作的。这里没有任何作业,即使使用=
运算符,它也是复制构造。
如果你向Test
类添加一个类似于你的构造函数和析构函数的拷贝构造函数,你应该清楚地看到它。
至于
t = Test();
此处使用Test()
创建临时对象。然后将该临时对象传递给Test
类的(编译器生成的)赋值运算符,然后立即销毁临时对象。
对象t
本身不会被破坏,它不应该是分配的目的地。
答案 1 :(得分:1)
您的混淆似乎是错误的期望,即在分配时原始对象被销毁。比如,在这段代码中:
cout << "Assignment 2" << endl;
t = Test();
这段代码调用move-assign运算符。既然你没有定义一个,那么编译器生成的默认值或多或少看起来像这样:
Test & operator=(Test &&) {}
请注意,该代码中没有构造函数或(严格地)析构函数的调用。将要运行的唯一构造函数和析构函数位于临时对象上(这是您在实际输出中观察到的)。在代码超出范围之前,原始对象不会被销毁;为什么会这样?在此之前你不能停止使用堆栈空间。
编辑:可能有助于您了解正在发生的事情:
#include<iostream>
struct Test {
Test() {std::cout << "Constructed.\n";}
~Test() {std::cout << "Destructed.\n";}
Test(Test const&) {std::cout << "Copy-Constructed.\n";}
Test(Test &&) {std::cout << "Move-Constructed.\n";}
Test & operator=(Test const&) {std::cout << "Copy-Assigned.\n"; return *this;}
Test & operator=(Test &&) {std::cout << "Move-Assigned.\n"; return *this;}
};
int main() {
std::cout << "Test t;\n";
Test t; //Construction
std::cout << "Test t2(t);\n";
Test t2(t); //Copy-Construct
std::cout << "Test t3(std::move(t2));\n";
Test t3(std::move(t2)); //Move-Construct
std::cout << "Test t4 = t;\n";
Test t4 = t; //Copy Construct, due to Copy Ellision
std::cout << "Test t5 = Test();\n";
Test t5 = Test(); //Will probably be a normal Construct, due to Copy Ellision
std::cout << "t = t2;\n";
t = t2; //Copy Assign
std::cout << "t = Test();\n";
t = Test(); //Move Assign, will invoke Constructor and Destructor on temporary
std::cout << "Done! Cleanup will now happen!\n";
return 0;
}
compiled here时的结果:
Test t;
Constructed.
Test t2(t);
Copy-Constructed.
Test t3(std::move(t2));
Move-Constructed.
Test t4 = t;
Copy-Constructed.
Test t5 = Test();
Constructed.
t = t2;
Copy-Assigned.
t = Test();
Constructed.
Move-Assigned.
Destructed.
Done! Cleanup will now happen!
Destructed.
Destructed.
Destructed.
Destructed.
Destructed.
DOUBLE EDIT COMBO!:
正如我在评论中提到的,val
只是一个指针。 8个字节(在64位计算机上)作为Test
存储的一部分分配。如果您尝试确保Test
始终包含尚未删除的val
的有效值,则需要实施Rule of Five(以前称为class Test {
float * val;
public:
Test() {val = new float;}
~Test() {delete val;
Test(Test const& t) {
val = new float(*(t.val));
}
Test(Test && t) {std::swap(val, t.val);}
Test & operator=(Test const& t) {
float * temp = new float(*(t.val)); //Gives Strong Exception Guarantee
delete val;
val = temp;
return *this;
}
Test & operator=(Test && t) {std::swap(val, t.val); return *this;};
float & get_val() const {return *val;} //Return by reference, not by pointer, to
//prevent accidental deletion.
};
三条规则):
#include <tuple>
#include <typeinfo>
template <typename F>
struct make_tuple_of_params;
template <typename Ret, typename... Args>
struct make_tuple_of_params<Ret (Args...)>
{
using type = std::tuple<Args...>;
};
template <typename F>
using make_tuple_of_params_t = typename make_tuple_of_params<F>::type;
template<typename F>
void some_magic_function(F f)
{
// if F is in the form void(double*, double*)
// make_tuple_of_params is std::tuple<double*, double*>
make_tuple_of_params_t<F> params;
// ...
}
void Foo(double* x, double* y) { }
int main()
{
some_magic_function(Foo);
}