头像

ywk




离线:10小时前


最近来访(4)
用户头像
MR.BOLT
用户头像
Helium7
用户头像
北高的某人
用户头像
error@warning

分享 类的大小

ywk
20小时前

我们在编写代码的过程中,常常会自定义类并进行实例化对象来完成我们的需求,这也是我们常说的面向对象编程。
而在我们编写代码的过程中,其实往往会忽视一个十分重要并且“有趣”的问题,就是每个类的大小是多少呢?
一个非常直观的感觉就是一个类的大小是由类的非静态成员变量决定的。而这句话其实只有在某些情况下是正确的。
第一个例子:

class A{

public:

    A()=default;

    char a;

    int b;

    char c;

};

请问A的大小是多少呢?一个最简单的答案是6个字节,因为char类型的大小是一个字节,int类型的大小是四个字节。
但这个答案一般情况下是不对的。我在自己电脑上跑出来的结果是12字节。这是为什么呢?这是因为在处理器实际分配内存的时候会考虑内存对齐的问题。
内存对齐有三个规则:
1. 非成员变量的对齐一般就是它的sizeof的值。
2. 对于类或者结构体内的变量还需要进行额外一次对齐。对齐的大小是由系统默认的对齐大小和类中sizeof值最大的成员变量共同决定的,取两者中的更小者。
3. 当类的每个成员变量计算完毕后,类的大小还必须满足是类中最大成员变量的整数倍。
根据这三个规则来分析A

class A{

public:

    A()=default;

    char a; //1字节  //根据规则2,1->4

    int b; //4字节  //根据规则2,4不变

    char c;//1字节 //根据规则2,1->4 
};
//class A根据规则1和2计算大小为12,符合规则3 故classA大小就是12

除此之外,类的大小还需要考虑虚函数和继承。



活动打卡代码 AcWing 802. 区间和

ywk
21小时前
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair<int,int> PII;
const int N=1e7+10;
int n,m;
vector<int> all;
vector<PII>add,query;
int a[N],s[N];
int find(int x)
{
    int l=0,r=all.size()-1;
    while(l<r)
    {
        int mid=(r-l)/2+l;
        if(all[mid]>=x)r=mid;
        else l=mid+1;
    }
    return r+1;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        int x,c;
        cin>>x>>c;
        add.push_back({x,c});
        all.push_back(x);
    }
    for(int i=0;i<m;i++)
    {
        int l,r;
        cin>>l>>r;
        query.push_back({l,r});
        all.push_back(l);
        all.push_back(r);
    }
    sort(all.begin(),all.end());
    sort(unique(all.begin(),all.end()),all.end());
    for(auto item:add)
    {
        auto x=find(item.first);
        a[x]+=item.second;
    }
    for(int i=1;i<=all.size();i++)s[i]=s[i-1]+a[i];
    for(auto item:query)
    {
        int l=find(item.first),r=find(item.second);
        cout<<s[r]-s[l-1]<<endl;
    }
    return 0;
}


活动打卡代码 AcWing 803. 区间合并

ywk
21小时前
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
int n;
struct f{
    int l,r;
}F[N];
int main()
{
    cin>>n;
    for(int i=0;i<n;i++){
        int l,r;
        cin>>l>>r;
        F[i]={l,r};
    }
    sort(F,F+n,[](const f& f1,const f& f2){
        return f1.l<f2.l;
    });
    int ed=F[0].r;
    int res=1;
    for(int i=1;i<n;i++)
    {
        if(F[i].l<=ed){
            ed=max(ed,F[i].r);   
        }else
        {
            res++;
            ed=F[i].r;
        }
    }
    cout<<res<<endl;
    return 0;
}


活动打卡代码 AcWing 898. 数字三角形

ywk
2天前
#include<iostream>
using namespace std;
const int N=510;
int f[N][N];
int n;
int dp[N][N];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            cin>>f[i][j];
        }
    }
    // for(int i=n;i>=0;i--)dp[n][i]=f[n][i];
    dp[1][1]=f[1][1];
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            if(j<i)
            {
                dp[i][j]=dp[i-1][j]+f[i][j];   
            }
            if(j>1){
                dp[i][j]=max(dp[i-1][j-1]+f[i][j],dp[i][j]);
            }
            if(j==i)
            {
                dp[i][j]=dp[i-1][j-1]+f[i][j];
            }

        }
    }
    int res=-2e9;
    for(int i=1;i<=n;i++)
    {
        res=max(res,dp[n][i]);
    }
    cout<<res<<endl;
    return 0;

}



ywk
5天前

前言

众所周知,智能指针其实也是模板类,智能指针实现内存分配和释放就是通过构造函数和析构函数实现的,接下来就简单说明一下shared_ptr的实现原理。

实现原理

  1. shared_ptr由于允许多个对象指向同一对象,所以拷贝构造和拷贝复制肯定是存在且需要定义的。
  2. shared_ptr又是如何判断是否可以释放内存呢?根据之前的文章可以知道,是通过一个引用计数来实现的,所以我们需要一个能够用来记录指针个数的成员变量,而单纯的int无法同步多个shared_ptr的值,所以我们最好采用int*类型的成员变量。
  3. 而智能指针本质就是指针,所以我们还需要利用模板来实现一个多种类型的成员指针。

代码实现

//shared_ptr的构造
#include<iostream>
#include<memory>
using namespace std;
template<typename T>
class Shared_ptr
{
public:
    Shared_ptr(T* ptr=NULL):count(new int (1)),ptr_(ptr){
        cout<<"构造"<<endl;
    }
    Shared_ptr(const Shared_ptr<T>& s):count(s.count),ptr_(s.ptr_){
        cout<<"拷贝构造"<<endl;
        // ++(*s.count);
        (*count) ++;
    }
    Shared_ptr<T> operator=(const Shared_ptr<T>& s){
        if(this!=&s){
            if(--(*(this->count))==0){
                delete this->count;
                this->count=nullptr;
                delete this->ptr_;
                this->ptr_=nullptr;
            }
            cout<<"拷贝赋值"<<endl;
            ptr_=s.ptr_;
            count=s.count;
            ++*(count);
            // ++*(s.count);
        }
    }
    int use_count()
    {
        return * count;
    }
    ~Shared_ptr()
    {
        --(*(this->count));
        if(*(this->count)==0)
        {
            delete this->count;
            this->count=nullptr;
            delete this->ptr_;
            this->ptr_=nullptr;
        }
    }
private:
    int* count;
    T* ptr_;
};
int main()
{
    int* t=new int(1);
    Shared_ptr<int> p(t);
    Shared_ptr<int>q=p;
    cout<<p.use_count()<<endl;
    cout<<q.use_count()<<endl;
    shared_ptr<int>p1=make_shared<int>(1);
    shared_ptr<int>q1=p1;
    cout<<p1.use_count()<<endl;
    cout<<q1.use_count()<<endl;
    return 0;
}



ywk
5天前

智能指针

众所周知,动态内存的管理是需要我们程序员自己手动操作的,一般是通过new和delete这一对运算符来完成的。而智能指针就是为了方便我们更好地管理内存空间,因为智能指针会自动地帮我们在使用完毕后释放指针的内存空间。这样的好处就在于可以避免有时我们忘记释放内存所导致的内存泄漏。

shared_ptr

shared_ptr就是智能指针中的一种,目前的标准库一般是有两种智能指针unique_ptr和shared_ptr,为了避免本文出现的循环引用问题,标准库还引入了一种weak_ptr。
unique_ptr和shared_ptr的不同就在于shared_ptr允许多个指针指向同一个对象,unique_ptr则是只允许一个指针指向一个对象,是“独占”式的指向。

循环引用

因为shared_ptr允许多个指针指向同一个对象,就无法避免地会存在A指向B,而B指向A的情况,在这种情况下就会导致shared_ptr无法正确地析构对象而导致内存泄漏。

#include<iostream>
#include<memory>
using namespace std;
class B;
class A{
public:
    A(){
        cout<<"A"<<endl;
    }
    ~A(){
        cout<<"delete A"<<endl;
    }
    shared_ptr<B>a_;
};
class B{
public:
    B(){
        cout<<"B"<<endl;
    }
    ~B(){
        cout<<"delete B"<<endl;
    }
    shared_ptr<A>b_;
};
int main()
{

    shared_ptr<A>a=make_shared<A>();
    shared_ptr<B>b=make_shared<B>();
    a->a_=b;
    b->b_=a;
    cout<<a.use_count()<<endl;
    cout<<b.use_count()<<endl;
    return 0;

}

上述代码跑出的结果是
A
B
2
2
能看到析构函数并没有被调用,因为没有出现delete A或delete B。而use_count()是属于shared_ptr的成员函数,它显示的是当前shared_ptr指向同一对象的智能指针数量。
而要解决这个循环引用问题,就需要我们之前提到的weak_ptr。
weak_ptr是弱共享的智能指针,它一般指向shared_ptr指向的对象,但并不会增加use_count的计数。
所以如果要解决这种循环引用的现象,就把A,B类内的shared_ptr的成员变量换成weak_ptr。



活动打卡代码 AcWing 282. 石子合并

ywk
5天前
#include<iostream>
using namespace std;
const int N=310;
int f[N];
int s[N];
int dp[N][N];
int n;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
        s[i]+=s[i-1];
    }

    for(int i=2;i<=n;i++)
    {
        for(int j=1;j+i-1<=n;j++)
        {
            int k=j+i-1;
            dp[j][k]=1e8;
            for(int t=j;t<k;t++)
            {
                dp[j][k]=min(dp[j][k],dp[j][t]+dp[t+1][k]+s[k]-s[j-1]);
            }
        }
    }
    cout<<dp[1][n]<<endl;
    return 0;
}





ywk
7天前

函数模板可以为不同的类型的参数生成不同类型的函数版本,调用函数模板的时候,编译器通常会根据函数实参来推断模板实参
但同时存在模板函数和普通函数时,如果函数实参符合普通函数的形参,这时候会直接调用普通函数,而不需要模板函数生成特定实例
当然我们也可以显示地指明我们想要调用的是模板函数

//测试函数模板
#include<iostream>
using namespace std;;

// template<int SIZE>
template<typename T>
T sum(T a,T b)
{
    cout<<"template function"<<endl;
    return a+b;
}

int sum(int a,int b)
{
    cout<<"function"<<endl;
    return a+b;
}
int main()
{
    sum(1,2);
    sum<int>(1,2);
    return 0;
}


活动打卡代码 AcWing 9. 分组背包问题

ywk
7天前
#include<iostream>
using namespace std;
const int N=110;
int n,v,s;
int f[N];
int V[N],W[N];
int main()
{
    cin>>n>>v;
    for(int i=0;i<n;i++)
    {
        cin>>s;
        for(int j=1;j<=s;j++)cin>>V[j]>>W[j];
        for(int k=v;k>=0;k--)
        {
            for(int j=1;j<=s;j++)
            {
                if(V[j]>k)continue;
                f[k]=max(f[k],f[k-V[j]]+W[j]);
            }
        }
    }
    cout<<f[v]<<endl;
    return 0;
}


活动打卡代码 AcWing 5. 多重背包问题 II

ywk
7天前
#include<iostream>
#include<vector>
using namespace std;
const int N=2e6+10;
int a[N],b[N];
int n,v;
int f[N];
int main()
{
    cin>>n>>v;
    int nums=1;
    // cout<<j<<endl;
    for(int i=1;i<=n;i++)
    {
        int a1,b1,s;
        cin>>a1>>b1>>s;
        for(int k=1;k<s;k*=2)
        {
            s-=k;
            a[nums]=k*a1;
            b[nums]=k*b1;
            nums++;
        }
        if(s>0){
            a[nums]=s*a1;
            b[nums]=s*b1;
            nums++;
        }
    }
    for(int i=1;i<nums;i++)
    {
        for(int k=v;k>=0;k--)
        {
            if(k>=a[i])f[k]=max(f[k],f[k-a[i]]+b[i]);
        }
    }
    cout<<f[v]<<endl;
    return 0;
}